Dynamic variable names: Difference between revisions
Line 98: | Line 98: | ||
=={{header|Genyris}}== |
=={{header|Genyris}}== |
||
The intern function creates a symbol from an arbitrary string. Defvar creates a binding. Weird symbols are quoted with pipe characters. |
The intern function creates a symbol from an arbitrary string. Defvar creates a binding. Weird symbols are quoted with pipe characters.<lang python> |
||
<lang python> |
|||
defvar (intern "This is not a pipe.") 42 |
defvar (intern "This is not a pipe.") 42 |
||
setq |This is not a pipe.| 2009 |
setq |This is not a pipe.| 2009</lang> |
||
</lang> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
Revision as of 07:33, 30 July 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.
See also
- Eval in environment is a similar task.
AutoHotkey
<lang AutoHotkey> InputBox, Dynamic, Variable Name %Dynamic% = hello ListVars MsgBox % %dynamic% ; says hello </lang>
BASIC
,
10 INPUT "Enter a variable name", v$ 20 KEYIN "LET "+v$+"=42"
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.
E
In E, there are no global variables, and there is no modification of the local (lexical) environment. However, it is possible to construct a program which binds any given variable name.
<lang e>def makeNounExpr := <elang:evm.makeNounExpr>
def dynVarName(name) {
def variable := makeNounExpr(null, name, null)
return e`{ def a := 1 def b := 2 def c := 3 { def $variable := "BOO!" [a, b, c] } }`.eval(safeScope)
}
? dynVarName("foo")
- value: [1, 2, 3]
? dynVarName("b")
- value: [1, "BOO!", 3]
? dynVarName("c")
- value: [1, 2, "BOO!"]</lang>
It is also possible to capture the environment object resulting from the evaluation of the constructed program and use it later; this is done by bindX
in Eval in environment#E (except for the program being constant, which is independent).
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.
Genyris
The intern function creates a symbol from an arbitrary string. Defvar creates a binding. Weird symbols are quoted with pipe characters.<lang python> defvar (intern "This is not a pipe.") 42 setq |This is not a pipe.| 2009</lang>
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>
Ruby
irb(main):001:0> varname = gets foo => "foo\n" irb(main):002:0> varname.chomp! => "foo" irb(main):003:0> eval "#{varname} = 42" => 42 irb(main):004:0> foo => 42 irb(main):005:0> puts "the value of #{varname} is #{eval varname}" the value of foo is 42 => nil
However, the dynamic variable is bound to the current context. Consider:
irb(main):006:0> def deref(v) irb(main):007:1> eval v irb(main):008:1> end => nil irb(main):009:0> deref varname NameError: undefined local variable or method `foo' for main:Object from (irb):7:in `deref' from (irb):9:in `eval' from (irb):7:in `deref' from (irb):9 from :0
Ruby lets you pass around the context as an object though:
irb(main):010:0> binding => #<Binding:0x7ff7d954> irb(main):011:0> def deref(v,b) irb(main):012:1> eval v, b irb(main):013:1> end => nil irb(main):014:0> deref varname, binding => 42 irb(main):015:0> puts "the value of #{varname} is #{deref varname, binding}" the value of foo is 42 => nil
Slate
Slate symbols are objects that name methods and slots. "Variable definition" is like defining a method which holds the value of a slot, and "variable access" is just method-call to get that value back. <lang slate> define: #name -> (query: 'Enter a variable name: ') intern. "X" define: name -> 42. X print. </lang>
Tcl
<lang Tcl>puts "Enter a variable name:" gets stdin varname set $varname 42 puts "I have set variable $varname to [set $varname]" </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>