Colons can be used as part of a variable name in Perl 6, together with angle brackets. These are apparently called extended identifiers, and are used to define things such as infix:<+>.
my $foo:bar = 3;
my $foo:bar<2> = 2;
my $foo:bar<baz> = 'quux';
say $foo:bar; # 3
say $foo:bar<2>; # 2 (and so on)
This creates identifiers with the same name in the current scope
say MY::.keys;
Prints ($=pod $_ $/ $buz !UNIT_MARKER $=finish EXPORT $foo:bar<2> $foo:bar<baz> $! ::?PACKAGE GLOBALish $bur::quux $¢ $foo:bar $?PACKAGE
But here's the thing.
say $foo:bar.kv; # prints key-value pairs.
print (0 3). So these coloned variables are creating a key-value pair. However, the other two "keys" (2 and baz) are not included in that set of key-value pairs. And if we really try to do say $foo:bar{'0'} or say $foo:bar<0>; we will obtain different errors, so there does not seem to be an actual way of using that as a real key. So I guess there are at least a couple of questions here:
Are these key-value pairs "real", or simply an unintended effect of something completely different?
If it is, can you define other values? Why are not the other "keys" included in that set?
Is there any user-facing way of getting all "angled" keys defined for a particular extended identifier? For instance, a way of obtaining all infix variables?
So these coloned variables are creating a key-value pair.
No, .kv (or kv) is producing the key-value pair:
my $foo = 3;
say kv $foo # (0 3)
When you call .kv on a list you get a list of indexes each followed by the associated value.
And every singular value will be treated as a list containing one value when you call a listy method on it.
Basically these are the same:
$foo:bar.kv
$foo:bar.list.kv
Related
Suppose I have several arrays in Ruby which I add/subtract values and afterwards I limit their range, like so:
array[x][y]=array[x][y]+1
array[x][y]=array[x][y].clamp (0..99)
Since I have many different arrays with rather long (index) names - and in order not to repeat those names twice in one line, I'd like to achieve something like
array[x][y]+=1.clamp (0..99)
Which is accepted by the interpreter, but doesn't work. It adds, but the value in the array does not get clamped.
Splitting it in at least two lines
array[x][y]+=1
array[x][y].clamp(0..99)
does also add, but doesn't clamp.
Is there any solution for this to fit the entire command in one line?
Many thanks!
The #clamp method doesn't take a range as a single argument for Ruby versions before 2.7, but rather two arguments representing the min and max, and #clamp does not mutate the object it's called on.
array[x][y] = (array[x][y] + 1).clamp(0, 99)
Note that because it's valid to call a method without parentheses, if parentheses are used around an argument list, there should not be any space between the method name and the parentheses. E.g. 1.clamp(0..4) rather than 1.clamp (0..4).
I use Array.wrap(x) all the time in order to ensure that Array methods actually exist on an object before calling them.
What is the best way to similarly ensure a Hash?
Example:
def ensure_hash(x)
# TODO: this is what I'm looking for
end
values = [nil,1,[],{},'',:a,1.0]
values.all?{|x| ensure_hash(x).respond_to?(:keys) } # true
The best I've been able to come up with so far is:
Hash::try_convert(x) || {}
However, I would prefer something more elegant.
tl; dr: In an app with proper error handling, there is no "easy, care-free" way to handle something that may or may not be hashy.
From a conceptual standpoint, the answer is no. There is no similar solution as Array.wrap(x) for hashes.
An array is a collection of values. Single values can be stored outside of arrays (e.g. x = 42) , so it's a straight-forward task to wrap a value in an array (a = [42]).
A hash is a collection of key-value pairs. In ruby, single key-value pairs can't exist outside of a hash. The only way to express a key-value pair is with a hash: h = { v: 42 }
Of course, there are a thousand ways to express a key-value pair as a single value. You could use an array [k, v] or a delimited string `"k:v" or some more obscure method.
But at that point, you're no longer wrapping, you're parsing. Parsing relies on properly formatted data and has multiple points of failure. No matter how you look at it, if you find yourself in a situation where you may or may not have a hash, that means you need to write a proper chunk of code for data validation and parsing (or refactor your upstream code so that you can always expect a hash).
In the "Well grounded Rubyist 2nd Edition", David Black states that (p.239):
The symbol table is just that: a symbol table. It’s not an object table. If you use an identifier for more than one purpose—say, as a local variable and also as a method name— the corresponding symbol will still only appear once in the symbol table
Then the author goes ahead and gives the following example:
>> Symbol.all_symbols.size
=> 3118
>> abc = 1
=> 1
>> Symbol.all_symbols.size
=> 3119
>> def abc; end
=> :abc
>> Symbol.all_symbols.size
=> 3119
My question is two-fold:
How is it possible to have the same identifier for more than one purpose!? - I understand that Ruby knows which one is which based on context but is this enough?
The symbol that was created in the example above, which identifier does it refer to? The local variable or the method name?
Great question.
Let's untangle this one by one.
"How is it possible to have the same identifier for more than one purpose!?"
"The symbol that was created, which identifier does it refer to?"
Let me first start with code that might look more familiar.
Obviously we can use the same string str to store two objects in two hashes
str = "max"
people[str] = Person.new
statistics[str] = 42
Now your example code does exactly the same
# pseudo-code
sym = :abc
locals[sym] = 1
methods[sym] = Method.new(...)
Internally Ruby represents everything using hashes
there is a hash with all classes
for each class there is a hash with all methods
for each instance there is a hash with all instance variables
for each method activation there is a hash with all local variables
et cetera
…
Symbols are used as keys into those hashes, and as such the same symbol can be used many times to map to many things in many hashes. Just the same way the code in your Rails app may use the same string as key in many different hash objects.
Now symbols are somewhat special. There is one and only one instance for :abc and Ruby uses a hash, yet another hash — the so-called symbol table — to map all symbols to an internal magic number. And then these magic numbers are used internally to refer to the symbol. I guess that is why the author of the book wrote "the symbols table is not an object table."
Mapping a string "abc" to these internal numbers is called "interning" and hence symbols are sometimes referred to as interned strings.
Fun fact, you can lookup these magic numbers yourself with :symbol.object_id and even infer from the order of numbers which symbols have been created first.
Hope that answers your question :)
I have not read the book, but the first two sentences seem to refer to the same questions you ask:
The symbol table is just that: a symbol table. It’s not an object table.
In other words - symbols can be names for identifiers, but they are not identifiers, nor do they have 1:1 mapping with identifiers directly (without context).
foo is an identifier. :foo is just the name of that identifier.
How is it possible to have two people named John? It's just a name, not an id.
Which person does the name John refer to? Depends on the context. In this case - the variable.
I can go into further details on how the actual resolution happens in the language if this question wasn't conceptual in nature.
I have this parameter as an array. The array is big, 100 cells. It is a parameter that can be initiated in omnet.ini file. The cells with even numbers should get value A and odd numbers should get value B. How can I do this in an automated manner?
Is there a way besides having all odd and even indices initiated one by one manually?
Wildcards can be useful but I do not know how to use them to separate odd and even indices.
Thanks.
You can access the actual module index with the index operator. Combining this with the conditional operator ?: you can easily define the value:
**.myModule[*].myParameter = index % 2 == 0 ? "A" : "B"
I'm not aware of any feature like this. There are a number of work-arounds you could use:
Provide two parameters and select the correct one in code
Use the volatile keyword (probably not appropriate here)
Put the entire thing in your .ini file
I'd personally implement the first approach, that way you can use the wildcard to pass both parameters ([*].myNode.parameterEven and [*].myNode.parameterUneven) and then set the correct values in your array in a for loop.
However, you could also use the volatile keyword in your NED file, see the manual for more details. However, this approach mostly works well if you have different parameters depending on which node you are assigning it to. For this case I think the first approach is better.
The last alternative is just putting the entire thing in your .ini file, which may be useful if you want to parameterize the array later.
Is it possible in Visual Foxpro to have 2 variables that point to the same address in memory. Such that if the value of one of the variables is changed then the other is also changed. I understand that when passing arguments to functions they can be passed by value or reference but I want to know if this is possible in straight code. I think in other languages such as C this is called a pointer but I don't believe VFP has pointers. So if one writes the following code it will output the number 4.
a=4
b=a
a=6
? b && answer 4
But could one write code such as the following where the answer could be 6?
a=4
b=*a && note the inclusion of the asterisk (pointer?) here which won't compile in VFP
a=6
? b
No. There are no pointers or references in Foxpro; as you note, the closest thing to it is passing parameters by reference to functions. You might be able to try to kludge something together (as Jerry mentions) with objects using Access/Assign methods, but even then, all that gets passed to the Assign method is the value being assigned - nothing about whether it was originally another variable, a literal value, an object's property, etc.
You could simulate it by using an array or a table. The variables would contain only the array index or record number (or other index) as a reference, and you'd have to get the actual value from the array or table.
Take a look at the Visual Foxpro Access and Assign Methods. These methods can be used to execute code when querying a property or trying to change the value of a property. Below is a link that shows an example:
Access and Assign Example
You could do something like this:
a=4
b='a'
a=6
?&b