Dynamic variable names

From Rosetta Code
Revision as of 19:12, 3 June 2009 by rosettacode>Mwn3d (-Java, the TOC will show up when it has four examples you don't need to add it yourself)
Task
Dynamic variable names
You are encouraged to solve this task according to the task description, using any language you may know.

Create a variable with a user-defined name. The variable name should not be written in the program text, but should be taken from the user dynamically.

AutoHotkey

<lang AutoHotkey> InputBox, Dynamic, Variable Name %Dynamic% = hello ListVars MsgBox % %dynamic%  ; says hello </lang>

Common Lisp

In Common Lisp, symbol objects name variables; symbols are produced from strings by way of read (general syntax) or intern (specificially retrieving or making a symbol).

Symbols are grouped into packages — roughly namespaces — and any time symbols are created at runtime it is usually good to explicitly specify what package they are created in, outside of user/developer tools for working from the REPL (interactive mode) where the current package *package* is appropriate.

Within the standard, every variable is either lexical or special (dynamic scope). There is no global lexical environment, so in order to "create a variable", we must either create our own mechanism to remember it for lexical binding in a later evaluation, or create a special variable. It is unspecified what happens when a symbol not lexically bound or declared special is used as a variable.

Every symbol has a value slot — a field which, roughly, contains its current value considered as a special variable.

Therefore, there are two parts to dynamically creating a variable: we must declare it special, and give it a value. The first part is accomplished by the proclaim function for making declarations at run-time. The second part is simply assigning to the value slot.

<lang lisp>(defun rc-create-variable (name initial-value)

 "Create a global variable whose name is NAME in the current package and which is bound to INITIAL-VALUE."
 (let ((symbol (intern name)))
   (proclaim `(special ,symbol))
   (setf (symbol-value symbol) initial-value)
   symbol))</lang>

<lang lisp> CL-USER> (rc-create-variable "GREETING" "hello") GREETING

CL-USER> (print greeting) "hello"</lang>

Things to note:

  • Once a symbol has been declared special, it cannot be used as a lexical variable. Because of this potentially-surprising behavior, it is conventional to give all symbols naming special variables distinguished names, typically by asterisks as in *greeting*, so that lexical variables will not accidentally be given those names.
  • Some implementations do, to some extent, support global non-special variables; in these, because of the preceding problem, it is better to simply set the value slot and not proclaim it special. However, this may provoke undefined-variable warnings since the compiler or interpreter has no information with which to know the symbol is intended to be a variable.
  • Common Lisp, by default, is case-insensitive; however it accomplishes this by canonicalizing read input to uppercase; there is syntax to denote a lower or mixed-case symbol name, |Foo| or F\o\o. intern does not go through the input path (reader), so we must provide the name in uppercase to make an "ordinary" variable name.

Forth

<lang forth>s" VARIABLE " pad swap move ." Variable name: " pad 9 + 80 accept pad swap 9 + evaluate</lang> Of course, it is easier for the user to simply type VARIABLE name at the Forth console.

Perl

<lang perl>print "Enter a variable name: "; $varname = <STDIN>; # type in "foo" on standard input chomp($varname); $$varname = 42; # when you try to dereference a string, it will be

               # treated as a "symbolic reference", where they
               # take the string as the name of the variable

print "$foo\n"; # prints "42"</lang>

PHP

<lang php><?php $varname = rtrim(fgets(STDIN)); # type in "foo" on standard input $$varname = 42; echo "$foo\n"; # prints "42" ?></lang>

Python

Works with: Python version 2.x

<lang python>>>> n = raw_input("Enter a variable name: ") Enter a variable name: X >>> exec n + " = 42" >>> X 42</lang>

Works with: Python version 3.x

<lang python>>>> n = input("Enter a variable name: ") Enter a variable name: X >>> exec(n + " = 42") >>> X 42</lang>

Tcl

<lang Tcl>puts "Enter a variable name:" gets stdin varname set $varname 0</lang> Note that it is more normal to use the user's name to index into a Tcl associative array, as the syntax gets easier to work with in that case: <lang tcl>puts -nonewline "Enter an element name: "; flush stdout gets stdin elemname set ary($elemname) [expr int(rand()*100)] puts "I have set element $elemname to $ary($elemname)"</lang>