is export and binding in Perl 6 - raku

Why isn't the value of a variable with := binding exported?
$ cat myModule.pm6
our $a is export = 42;
our $b is export := $a;
$ cat program.p6
use myModule;
say $a;
say $b;
$ perl6 program.p6
42
(Any) # Why?

An our-scoped variable is really just a lexical variable (like my) that - instead of having a Scalar freshly created per scope - is initialized by being bound to a symbol of that name in the Stash of the current package. So effectively, this:
our $foo;
Is doing this:
my $foo := $?PACKAGE.WHO<$foo>;
And so:
our $foo = 42;
Is doing this:
(my $foo := $?PACKAGE.WHO<$foo>) = 42;
Rebinding the symbol thus means it's no longer associated with the Scalar container stored in the Stash.
Exporting an our-scoped variable exports the Scalar container from the stash that the variable is bound to at scope entry time. Thus the assignment assigns into that exported Scalar container. By contrast, binding replaces the lexical with something entirely different and unrelated to what was exported.
This is why you aren't allowed to export a my-scoped variable: a fresh Scalar is bound every scope entry, but exportation is a compile-time thing, so there would be no way to ever modify the thing that was exported.

Related

How can I check whether a variable has a buffer-local value in Emacs `org-mode`?

How can I check that the value for org-drill-cram-hours has been set in the buffer (emacs-org-mode)?
# Local Variables:
# org-drill-cram-hours: 0
# org-drill-hide-item-headings-p: t
# End:
I have the above in the TOP OF MY org-mode buffer.
I re-opened the file using C-x C-v after adding these values.
I don't think the local variable value is set, cause when I run org-drill-cram, it does not do what is expected (go over all the buffer points i.e.).
I want to check the local value set for org-drill-cram-hours, but when I do C-h v org-drill-cram-hours, I don't see the buffer-local value.
org-drill-cram-hours is a variable defined in ‘org-drill.el’.
Its value is 12
What am I missing? I don't want to use setq or C-h v variable to SET the value.
P.S.
(However if I change the variable value through C-h v var, then org-drill-cram works as expected.)
Just use C-h v org-drill-cram-hours with that buffer current.
That tells you (1) the buffer-local value, if there is one, and (2) the global value. If it doesn't specify a buffer-local value then you haven't defined one for that buffer.
For example, if buffer foobar has a buffer-local value then C-h v org-drill-cram-hours shows this:
org-drill-cram-hours is a variable defined in `org-drill.el'.
Its value is 0
Original value was 12
Local in buffer foobar; global value is 12

TCL, How to name a variable that includes another variable

In TCL, I'm writing a procedure that returns the depth of a clock.
But since I have several clocks I want to name the var: depth_$clk
proc find_depth {} {
foreach clk $clocks {
…
set depth_$clk $max_depth
echo $depth_$clk
}
}
But I get:
Error: can't read "depth_": no such variable
Use error_info for more info. (CMD-013)
Your problem is this line:
echo $depth_$clk
The issue is that the syntax for $ only parses a limited set of characters afterwards for being part of the variable name; the $ is not part of that. Instead, you can use the set command with one argument; $ is effectively syntactic sugar for that, but the command lets you use complex substitutions.
echo [set depth_$clk]
HOWEVER!
The real correct thing to do here is to switch to using an associative array. It's a bit larger change to your code, but lets you do more as you've got proper access to substitutions in array element names:
proc find_depth {} {
foreach clk $clocks {
…
set depth($clk) $max_depth
echo $depth($clk)
}
}
echo ${depth}_$cell
This can help too.
Thanks !

Sharing variables between C Shell and TCL

I have a variable which is being used in two separate scripts: a C Shell one and a TCL one. Is there a way to define it just once and access it in both the scripts?
vars.sh
#!/usr/bin/env tcsh
set a=b
run.sh
#!/usr/bin/env tcsh
source vars.sh
echo $a
vars.tcl
#!/usr/bin/env tclsh
set a b
run.tcl
#!/usr/bin/env tclsh
source vars.tcl
puts $a
I do not like to idea of generating two separate files to store the same variables in two different formats. Is there a way to use a single vars file and have the variables available to both C Shell and TCL?
The simplest method is to make the variables be environment variables, since those are inherited by a child process from their parent. (On the Tcl side, they're elements in the ::env global array, and on the C shell side, they can be read like any other variable but need to be set via setenv.)
Sharing a single configuration file is much harder, since the two languages use a different syntax. Provided you don't use anything complicated in the way of quoting, you can make Tcl parse the C shell format.
proc loadVariablesFromCshellFile {filename arrayName} {
upvar 1 $arrayName array
set f [open $filename]
while {[gets $f line] >= 0} {
if {[regexp {^\s*set (\w+)=([""'']?)(.*)\2\s*$} $line -> key quote value]} {
set array($key) $value
}
}
close $f
}
This isn't complete code, since it doesn't handle substitution of variables inside the value, but it is enough to get you started. (I also hope you're not using that feature; if you are, portability is going to be quite a bit harder to achieve.) Here's how you'd use it:
#!/usr/bin/env tclsh
proc loadVariablesFromCshellFile {filename arrayName} {
upvar 1 $arrayName array
set f [open $filename]
while {[gets $f line] >= 0} {
if {[regexp {^\s*set (\w+)=([""'']?)(.*)\2\s*$} $line -> key quote value]} {
set array($key) $value
}
}
close $f
}
loadVariablesFromCshellFile vars.sh myvars
puts $myvars(a)
While it is entirely possible to load the values straight into scalar globals on the Tcl side, I really don't recommend it as it is polluting the global variable space from a source outside the Tcl program, a known piece of poor practice.

TCL/Expect variable vs $variable

Which one is proper way of using variable with or without dollar sign? I thought that variable (without $) is used only during variable declaration (similar to Bash):
set var 10
In all other cases when variable is referred or used (but not declared) the proper syntax is $variable (with $):
set newVar $var
puts $var
puts $newVar
But then I found code where it is interchanged and seems that this code is working:
# using argv
if {[array exists argv]} {
puts "argv IS ARRAY"
} else {
puts "argv IS NOT AN ARRAY"
}
# using $argv
if {[array exists $argv]} {
puts "\$argv IS ARRAY"
} else {
puts "\$argv IS NOT AN ARRAY"
}
# using argv
if {[string is list argv]} {
puts "argv IS LIST"
} else {
puts "argv IS NOT LIST"
}
# using $argv
if {[string is list $argv]} {
puts "\$argv IS LIST"
} else {
puts "\$argv IS NOT LIST"
}
Output:
argv IS NOT AN ARRAY
$argv IS NOT AN ARRAY
argv IS LIST
$argv IS LIST
Edit in reply to #glenn jackman:
Your reply pointed me to further research and I've found that TCL is capable doing some sort of "self modifying code" or whatever is correct name e.g.:
% set variableName "x"
x
% puts $x
can't read "x": no such variable
% set $variableName "abc"
abc
% puts $x
abc
% puts [set $variableName]
abc
%
%
%
%
%
%
% set x "def"
def
% puts $x
def
% puts [set $variableName]
def
%
Now your answer bring some light to problem, but one question remains. This is excerpt from documentation:
set varName ?value?
array exists arrayName
Documentation says that both functions expect variable name (not value) in other words it expect variable instead of $variable. So I assume (based on above self modifying code) that when I pass $variable instead of variable the variable substitution took place (exactly the same as code above). But what if $variable contains something that is not a list neither array (my arguments during testing was: param0 param1 "param 2" param3). From this point of view the output that says $argv IS LIST is wrong. What am I missing here?
Edit in reply to #schlenk:
Finally I (hope) understand the problematic. I've found great article about TCL, which explain (not just) this problematic. Let me pinpoint a few wise statement from this article:
In Tcl what a string represents is up to the command that's
manipulating it.
Everything is a command in Tcl - as you can see there is no
assignment operator.
if is a command, with two arguments.
The command name is not a special type but just a string.
Also following SO answer confirms this statement:
"In Tcl, values don't have a type... they question is whether they can be used as a given type."
The command string is integer $a means:
"Can I use the value in $a as an integer"
NOT
"Is the value in $a an integer"
"Every integer is also a valid list (of one element)... so it can be
used as either and both string is commands will return true (as will
several others for an integer)."
I believe the same applies also for string is list command:
% set abc "asdasd"
asdasd
% string is list $abc
1
% string is alnum $abc
1
string is list returns 1 because $abc is string and also it is one element list etc. In most tutorials there are said that following snippet is the proper way of declaring and working with lists:
% set list1 { 1 2 3 }
% lindex $list1 end-1
2
But when everything in TCL is string the following is also working in my experience (if I am wrong correct me please).
% set list2 "1 2 3"
1 2 3
% lindex $list2 end-1
2
It depends on the command. Some Tcl commands require a variable name as a parameter, if they need to modify the contents of the variable. Some are:
set
foreach
lappend
incr
Most but certainly not all commands want to take a variable's value.
You'll need to check the documentation for the relevant commands to see if the parameters include "varName" (or "dictionaryVariable"), or if the parameters are named as "string", "list", etc
An example using info exists which takes a varName argument:
% set argv {foo bar baz}
foo bar baz
% info exists argv ;# yes the variable "argv" exists
1
% info exists $argv ;# no variable named "foo bar baz"
0
% set {foo bar baz} "a value" ;# create a variable named "foo bar baz"
a value
% info exists $argv ;# so now that variable exists
1
The important thing to know is that $x in Tcl is just syntactical sugar for the command set x. So you can translate any $x in Tcl code into [set x] in the same place to see what really happens.
The other important thing to consider is immutable values. Tcl values are immutable, so you cannot change them. You can just create a new changed value. But you can change the value stored inside a variable.
This is where the difference between commands taking a variable name and those that take a value comes in. If a command wants to change the value stored in a variable, it takes a variable name. Examples are lappend, lset, append and so on. Other commands return a new value and take a value as argument, examples include lsort, lsearch, lindex.
Another important point is the fact that you do not really have a list type. You have strings that look like lists. So that is what Tcl's string is list tests. This has some consequences, e.g. you cannot always decide if you have a string literal or a one item list, as it is often the same. Example given:
% set maybe_list a
% string is list $maybe_list
1
Combine that with Tcls nearly unrestricted names for variables, as already demonstracted by Glenn and you can get really confused. For example, these are all valid Tcl variable names, you just cannot use all of them with the $ shortcut:
% set "" 1 ;# variable name is the empty string
1
% puts [set ""]
% set " " 1 ;# variable name is just whitespace
1
% puts [set " "]
1
% set {this is a list as variable name} 1 ;# a variable with a list name
1
% puts [set {this is a list as variable name}]
1
% set Δx 1
1
% incr Δx
2
% puts [set Δx]
2

How to get fully expanded gnu make variable value

I'm trying pass the fully evaluated value of a recursive make variables to a $(shell ...). I've tried many ways, including a macro to compute the final value myself, but have not had success.
I'm getting the intermediate variable syntax in my shell instead of the fully expanded recursive variable value.
VAR1 ?= var1_value
VAR2 ?= var2_value1 var2_value2
VAR3 ?= $(VAR1)
VARLIST := VAR1 VAR2 VAR3
quote = $(if $(call ne,$(words $(1)),1),"$(1)",$(1))
GENVARS1 = $(foreach v,$(1),set $(v) $(call quote,$(value $(v)));)
SHELLVARLIST = $(shell echo $(call GENVARS1,$(VARLIST)))
shelltest :
#echo "--->Executing recipe for shelltest"
#echo "VAR3 is $(VAR3)"
$(call GENVARS,$(VARLIST))
#echo "SHELLVARLIST = $(SHELLVARLIST)"
In an ordinary dereference (at least in a recipe), the variable is fully expanded. However, when passed to macro as an argument, it does not. Is there any way to get the fully expanded value into a macro argument?
Here's the result when running make:
bash-4.1$ make -f test_expand.mk shelltest
/bin/sh: VAR1: command not found
--->Executing recipe for shelltest
VAR3 is var1_value
set VAR1 var1_value; set VAR2 var2_value1 var2_value2; set VAR3 $(VAR1);
/bin/sh: VAR1: command not found
SHELLVARLIST = set VAR1 var1_value
As you can see, $(VAR3) does not get passed as "var1_value" but instead gets passed as the literal "$(VAR1)".
Any hints or pointers would be most welcome. This is hair-pullingly frustrating (and I have so little left... :-o)
Thanks,
Dave
You are explicitly telling make to NOT expand the variable, by using the $(value $(V)) construct. That's what the value function does: avoids expansion.
If you want expansion, get rid of the value function. Why did you add it there in the first place?
GENVARS1 = $(foreach v,$(1),set $(v) $(call quote,$(v));)
ETA
Sorry, if you want the expansion of the value as a variable name, you need to add an extra level of $(...) to expand it:
GENVARS1 = $(foreach v,$(1),set $(v) $(call quote,$($(v)));)
The inner $(v) expands to the name of the variable such as VAR3, so then the outer $(...) will be $(VAR3) and expand to the value of the VAR3 variable.