# What is the recommended way to assign a value to a variable and retrieve it for later use?

What is the recommended way to define a variable inside a document and retrieve its value later?

I've googled several different solutions, usually about ~10 lines long. I was wondering, that there must be a shorter way of doing something like this (Pseudocode):

\setvalue(VARIABLE1){foo foo bar}


and later in the document

$\getvalue(VARIABLE1)$.


I've also seen solutions that include defining a new command, but what if that command is already used inside another package? That doesn't really seem like an independent solution.

-
As noted in my answer, newcommands can't conflict with an existing command without telling you. LaTeX doesn't let you overwrite with it. – qubyte Dec 4 '11 at 19:00


% Set your new variable. In this case it will be
% called "\MyNewVariable" and the value will be "hello".
\newcommand{\MyNewVariable}{hello}

% Use to get the variable.
\MyNewVariable


If you could prepend them all with your name or some other mnemonic, then you're unlikely to get clashes. This mnemonic then behaves as your own (sort of) namespace.


-
As I said, probably not what you're looking for, but it is minimal. – qubyte Dec 4 '11 at 18:18

Sounds like you're looking for a key-value system. May I suggest pgfkeys? Including Yiannis' idea of using properties for each variable, I'd do it like this:

\documentclass{article}
\usepackage{pgfkeys}

\newcommand{\setvalue}[1]{\pgfkeys{/variables/#1}}
\newcommand{\getvalue}[1]{\pgfkeysvalueof{/variables/#1}}
\newcommand{\declare}[1]{%
\pgfkeys{
/variables/#1.is family,
/variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
}%
}

\declare{}

\begin{document}
\setvalue{VARIABLE1 = foo foo bar}
\getvalue{VARIABLE1}

\declare{test/}
\setvalue{test/property = 12}
\getvalue{test/property}
\end{document}


Less than ten lines, even counting the ones that have only braces. The operation is very simple: pgfkeys stores variables as "files" in "directories"; I've decided that yours should be in the /variables directory, so not in the global namespace. (By the way, pgfkeys keys never conflict with normal macro names, so its "global namespace" is different from the macros namespace.)

The \setvalue macro just changes directory appropriately and then calls your assignment. The \getvalue macro retrieves the variable from the correct directory.

The only trick is that in pgfkeys, a key needs to be "known" before it is assigned, or else you have to call it as key/.initial = value. Since I don't want to force you to write that, I created a "handler" for unknown variables that just adds this piece of code behind the scenes.

You declare a variable with properties using \declare{variable/}, and then you can use variable/property as a variable name in \setvalue (you can also use variable/ as a default directory, so write

\setvalue{variable, property 1 = value 1, property 2 = value 2}


which is convenient). The \declare macro just sets up the unknown handler for the "directory" /variables/variable/ (which means that the cryptic line \declare{} at the beginning sets up the /variables/ directory itself).

-
It seems that you have a small typo in your definition of setvalue/getvalue. Your code as is worked for me with \declare{}, but returned error while \setvalue with \declare{abc}. It workes well though when I corrected setvalue to: \newcommand{\setvalue}[1]{\pgfkeys{/variables/#1}}. – Artem Pelenitsyn Jul 24 '14 at 18:19
@Artem Strange that this went unfixed for so long. Thanks! – Ryan Reich Jul 24 '14 at 18:22

I would rather define them using a sort of a Lisp way, or object orientated way.

In the minimal below, we use:

\setproperty{test}{aproperty}{12}
\getproperty{test}{aproperty}


Think of them as representing test.aproperty (we actually define them a test@paproperty), this way it is highly unlikely to conflict with any existing commands, other than possibly your own:

The minimal:

\documentclass{article}
\makeatletter
%  Properties a la Lisp.
\def\ece#1#2{\expandafter#1\csname#2\endcsname}%
% \setproperty{ATOM}{PROPNAME}{VALUE} defines the property PROPNAME on the
% atom'' ATOM to have VALUE.
%
\def\setproperty#1#2#3{\ece\protected@edef{#1@p#2}{#3}}%
\def\setpropertyglobal#1#2#3{\ece\protected@xdef{#1@p#2}{#3}}%
%
%
% \getproperty{ATOM}{PROPNAME} expands to the value of the property
% PROPNAME on ATOM, or to nothing (i.e., \empty), if the property isn't
% present.
%
\def\getproperty#1#2{%
\expandafter\ifx\csname#1@p#2\endcsname\relax
% then \empty
\else \csname#1@p#2\endcsname
\fi
}%
%
\makeatother

\begin{document}
\setproperty{test}{aproperty}{12}
\getproperty{test}{aproperty}
\end{document}

-
Instead of \edef and \xdef, maybe \protected@edef and \protected@xdef should be used, so as to allow very general values. – egreg Dec 4 '11 at 23:17

Your code is almost valid ConTeXt: you define a variable using

\setvalue{variable1}{value}


and can get its value using

\getvalue{variable1}


(These are similar to \@namedef and \@nameuse in LaTeX). If you want key-value driven variables, you can use:

\definenamespace
[VAR]
[
name=VAR,
setup=list,
command=list,
parent=VAR,
]

\setupVAR
[a={default A},
b={default B}]

\defineVAR
[set1]
[a={set1 A},
c={set1 C}]

\defineVAR
[set2]
[b={set2 B},
c={set2 C}]

\starttext
\startlines
\namedVARparameter{set1}{a} % gives set1 A
\namedVARparameter{set1}{b} % gives default B
\namedVARparameter{set1}{c} % gives set1 C
\stoplines
\stoptext

-

\newtoks\myvar
\myvar={foo bar baz}


and later on in the document when you want to use it:

\the\myvar

-

A solution with the prop module from LaTeX3:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\setproperty}{ O{standard} m m }
{
\cs_if_exist:cF { g_citr_#1_prop } { \prop_new:c { g_citr_#1_prop } }
\prop_gput:cnn { g_citr_#1_prop } { #2 } { #3 }
}
\NewDocumentCommand{\getproperty}{ O{standard} m }
{
\cs_if_exist:cTF { g_citr_#1_prop }
{
\prop_get:cnN { g_citr_#1_prop } { #2 } \l_citr_value_tl
\quark_if_no_value:NTF \l_citr_value_tl
{
Inexistent~property~#2
}
{
\tl_use:N \l_citr_value_tl
}
}
{
Inexistent~family~#1
}
}
\prop_new:N \g_citr_standard_prop
\tl_new:N \l_citr_value_tl
\ExplSyntaxOff

\begin{document}
\setproperty[test]{aproperty}{12}
\getproperty[test]{aproperty}

\getproperty[test]{bproperty}

\setproperty{cproperty}{42}

\getproperty{cproperty}

\end{document}


There is a "standard" property list set; others can be defined and accessed with the optional argument to \setproperty or \getproperty.

-

There are already enough solutions for you. I give the following because your question provides me an opportunity to test a new feature of pathkeys package. Please don't give \NewVariables the name \newvariables. The latter is an internal command in a package. That will be changed soon.

\documentclass{article}
\usepackage{pathkeys}
\makeatletter
\newcommand\setvalues[1]{\pathkeys{citronas/var/set:#1}}
\newcommand\getvalue[1]{\pathkeysval{citronas/var/#1}}
\def\variablelist{}
\newcommand\NewVariables[1]{%
\cptfor#1\dofor{%
\def\reserved@a####1=####2=####3\@nil{%
}%
\reserved@a##1==\@nil
}%
\cptexpanded{\pathkeys{citronas/var/define*:\expandcsonce\variablelist}}%
}
\makeatother
\NewVariables{%
var1 = default value1,
var2 = defaultvalue2
}
\setvalues{var1=new value1, var2=new value2}
\edef\x{\getvalue{var1}}

\begin{document}
\getvalue{var1}
\end{document}


Version 0.0.3 of ltxkeys package (to be uploaded on 2011/12/09) will allow you to do things like the following:

\declarevariables[mynamespace]{%
var1 = {default value1} = \def\mycolor{#1}\def\cmd##1{##1},
var2 = default value2, % No callback
var3 % no default value and no callback
}

\setvarvalues[mynamespace]{var1=new value1, var2=new value2}

\edef\x{\getvarvalue[mynamespace]{var1}}

\begin{document}
\getvarvalue{fam/subfam}{var1}
\end{document}


[mynamespace] will be optional. That means that, to keep \getvarvalue expandable, we need an expandable \@testopt. One can be designed but Joseph Wright, if I got him right the other time, doesn't seem to be comfortable with any expandable \@testopt. My tests have so far revealed nothing worrisome about them. With some luck Joseph will confirm or refute his objection here.

-