Here is a supplement to your excellent answer.
The three variations below always produce the same result:

How to use a family to define its own keys
Here, I define the new family /tikz/my grid
with two new keys /tikz/my grid/rows
and /tikz/my grid/columns
. But the user and the developer must know and use the name of this family to use these keys.
\documentclass{standalone}
\usepackage{tikz}
\tikzset{
% define a family
my grid/.is family,
% use it to define the other keys,
my grid,
% set the initial values (if the key is not called)
rows/.initial=1,
columns/.initial=1,
% set the default values (if the key is called without value)
rows/.default=2,
columns/.default=2,
}
\tikzset{
% the code for the pic
pics/grid/.style={
code={
% to get the value we use \tikzset (!) with the .get handler to put it in a macro
\tikzset{my grid/rows/.get=\rows}
\tikzset{my grid/columns/.get=\columns}
% then we can use the \rows and \columns macros to draw the pic
\foreach \i in {1,...,\columns} {
\foreach \j in {1,...,\rows} {
\draw (\i,\j) circle [radius=3mm];
}
}
}
}
}
\begin{document}
\begin{tikzpicture}
\path (0,0) pic[my grid/rows=5,my grid/columns=3] {grid};
\path (5,0) pic[my grid/rows=2,my grid/columns=2] {grid};
\path (10,0) pic[my grid/rows] {grid}; % rows defaults to 2, columns keeps its initial value (1)
\end{tikzpicture}
\end{document}
How to use its own keys in the parameter of the grid
pic
Here, I use the parameter of the grid
pic to get the keys provided by the user. I can freely choose my family name since the user no longer needs it.
But the pic developer must know and use the name of this family many times to use these keys.
\documentclass{standalone}
\usepackage{tikz}
\tikzset{
% define a family
my grid parameters/.is family,
% use it to define the other keys,
my grid parameters,
% set the initial values (if a key is not called)
rows/.initial=1,
columns/.initial=1,
% set the default values (if a key is called without value)
rows/.default=2,
columns/.default=2,
}
\tikzset{
% the code for the pic
pics/grid/.style={% a style (or a key) can use one parameter by default
code={
\tikzset{my grid parameters,#1}
% to get the value we use \tikzset (!) with the .get handler to put it in a macro
\tikzset{my grid parameters/rows/.get=\rows}
\tikzset{my grid parameters/columns/.get=\columns}
% then we can use the \rows and \columns macros to draw the pic
\foreach \i in {1,...,\columns} {
\foreach \j in {1,...,\rows} {
\draw (\i,\j) circle [radius=3mm];
}
}
}
}
}
\begin{document}
\begin{tikzpicture}
\path (0,0) pic {grid={rows=5,columns=3}};
\path (5,0) pic {grid={rows=2,columns=2}};
\path (10,0) pic {grid={rows}}; % rows defaults to 2, columns keeps its initial value (1)
\end{tikzpicture}
\end{document}
How to use its own macros to store the value of its own keys
Here, I use the parameter of the grid
pic to get the keys provided by the user and I use the .store in
handler to store the value of key in my own macros. I can freely choose my family name since the user no longer needs it. In the grid
pic, the developer uses the family name one time but must know and use the name of my own macros.
\documentclass{standalone}
\usepackage{tikz}
\tikzset{
% define a family
my grid parameters/.is family,
% use it to define the other keys,
my grid parameters,
% define keys to store its value in a specific macro
rows/.store in=\mygridrows,
columns/.store in=\mygridcolumns,
% store the global initial values (if a key is not called)
rows=1,
columns=1,
% set the default values (if a key is called without value)
rows/.default=2,
columns/.default=2,
}
\tikzset{
% the code for the pic
pics/grid/.style={% a style (or a key) can use one parameter by default
code={
\tikzset{my grid parameters,#1}
% the values are already stored in specific macros then we can use
% the \mygridrows and \mygridcolumns macros to draw the pic
\foreach \i in {1,...,\mygridcolumns} {
\foreach \j in {1,...,\mygridrows} {
\draw (\i,\j) circle [radius=3mm];
}
}
}
}
}
\begin{document}
\begin{tikzpicture}
\path (0,0) pic {grid={rows=5,columns=3}};
\path (5,0) pic {grid={rows=2,columns=2}};
\path (10,0) pic {grid={rows}}; % rows defaults to 2, columns keeps its initial value (1)
\end{tikzpicture}
\end{document}
pic {grid={rows=5, columns=3}}
instead ofpic[rows=5, columns=3] {grid}
. This is better than nothing but seems like a weird hack, so I'd really like to know how to do it "properly", if it can be done.