Dynamic variable names: Difference between revisions
(moving "where it came from" category to talk page) |
(→{{header|Common Lisp}}: expand, pedantically) |
||
Line 11: | Line 11: | ||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
<lang lisp>(defmacro set-string (string value) |
|||
In Common Lisp, symbol objects name variables; symbols are produced from strings by way of <code>read</code> (general syntax) or <code>intern</code> (specificially retrieving or making a symbol). |
|||
`(setf |
|||
,(read-from-string string) |
|||
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'' <code>*package*</code> is appropriate. |
|||
,value)) |
|||
(set-string "dynamicA" "hello") |
|||
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. |
|||
(print dynamicA)</lang> |
|||
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 <code>proclaim</code> 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 <code>*greeting*</code>, so that lexical variables will not accidentally be given those names. |
|||
* Some implementations <!-- XXX citation --> 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, <code>|Foo|</code> or <code>F\o\o</code>. <code>intern</code> does not go through the input path (''reader''), so we must provide the name in uppercase to make an "ordinary" variable name. |
|||
=={{header|Forth}}== |
=={{header|Forth}}== |
Revision as of 13:21, 3 June 2009
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|
orF\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
<lang python>>>> n = raw_input("Enter a variable name: ") Enter a variable name: X >>> exec n + " = 42" >>> X 42</lang>
<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>