Destructuring assignment in object creation - arrays

As with my previous question, this is an area where I can't tell if I've encountered a bug or a hole in my understanding of Raku's semantics. Last time it turned out to be a bug, but doubt lightning will strike twice!
In general, I know that I can pass named arguments to a function either with syntax that looks a lot like creating a Pair (e.g. f :a(42)) or with syntax that looks a lot like flattening a Hash (e.g., f |%h). (see argument destructuring in the docs). Typically, these two are equivalent, even for non-Scalar parameters:
sub f(:#a) { dd #a }
my %h = a => [4, 2];
f :a([4,2]); # OUTPUT: «Array element = [4, 2]»
f |%h; # OUTPUT: «Array element = [4, 2]»
However, when constructing an object with the default .new constructor, these two forms seem to give different results:
class C { has #.a; }
my %h = a => [4, 2];
C.new: :a([4,2]; # OUTPUT: «C.new(a => ([[4, 2]])»
C.new: |%h; # OUTPUT: «C.new(a => [[4, 2],])»
That is, passing :a([4,2]) results in a two-element Array, but using the argument-flattening syntax results in a one-element Array containing a two-element Array.
Is this behavior intended? If so, why? And is there syntax I can use to pass |%h in and get the two-element Array bound to an #-sigiled attribute? (I know using an $-sigiled attribute works, but I prefer the semantics of the #).

Is this behavior intended?
Yes. Parameter binding uses binding semantics, while attribute initialization uses assignment semantics. Assignment into an array respects Scalar containers, and the values of a Hash are Scalar containers.
If so, why?
The intuition is:
When calling a function, we're not going to be doing anything until it returns, so we can effectively lend the very same objects we pass to it while it executes. Thus binding is a sensible default (however, one can use is copy on a parameter to get assignment semantics).
When creating a new object, it is likely going to live well beyond the constructor call. Thus copying - that is, assignment - semantics are a sensible default.
And is there syntax I can use to pass |%h in and get the two-element Array bound to an #-sigiled attribute?
Coerce it into a Map:
class C { has #.a; }
my %h = a => [4, 2];
say C.new: |%h.Map;
Or start out with a Map in the first place:
class C { has #.a; }
my %h is Map = a => [4, 2];
say C.new: |%h;

Related

Why is one of these functions changing the original array and not the other?

I'm not sure what I am missing by looking at these three functions.
The desired result for these functions would be that the original array changes value so
change_this = [6, 7, 8]
array_times_two!(change_this)
change_this == [12, 14, 16] => true
The following function does this
def array_times_two!(array)
array.map! {|x| x * 2}
end
And so does this one...
def array_times_two!(array)
array.each_with_index do |element, index|
array[index] = array[index] * 2
end
array
end
How come the following function does not change the value like the others?
def array_times_two!(array)
array = array.map {|x| x * 2}
array
end
How is the second function changing the array but the third isn't?
In the last example you have array coming in as a local variable. Reassigning the local variable has zero effect on the original variable. This is because Ruby is, in effect, pass by value, except the confusing part is those values are often object references, or a fancy term for pointers.
The consequences of this aren't that complicated though: Calling a method on an object can modify the contents of that object. Reassigning a variable cannot.
The first version of your method is probably the best, but you could make it more generic, like:
def multiply_by!(array, n = 2)
array.map! { |v| v * n }
end
You can also "fix" the last version by using a method call to apply the changes:
def array_times_two!(array)
array.replace(array.map {|x| x * 2})
end
This calls Array#replace to stomp the contents of the original object and force the changes to stick. It's not a very elegant solution when things like map! exist.

Meaning of `#$array` and other constructs

I am still learning Perl 6. Please pardon my ignorance. I am reading the Operators page and I found some unfamiliar constructs at the start of a table:
A Level Examples
N Terms 42 3.14 "eek" qq["foo"] $x :!verbose #$array
I re-read class Array and class Scalar but I am unable to find #$xyz construct in those sections. What do :! and #$ mean? Is there a convenient place that gathers and explains all these symbolic constructs?
Thank you very much !!
#$foo is short for #($foo), where $foo is an item variable and the #(...) syntax simply calls the .list method on its argument. Both the method and the syntactic form are sometimes called the "list/array contextualizer".
One use for it, is when you want to iterate over an Array stored in an item container. An item container is considered a single item by built-ins such as for loops, whereas calling .list on it returns the plain Array without the surrounding item container (i.e. "forces the value to be interpreted in list context"):
my $foo = [1, 2, 3];
say $foo.perl; # $[1, 2, 3]
say $foo.list.perl; # [1, 2, 3]
say #$foo.perl; # [1, 2, 3]
for $foo { ... } # One iteration
for $foo.list { ... } # Three iterations
for #$foo { ... } # Three iterations (identical to the previous line)
:!foo is short for :foo(False), i.e. a named argument that has the value False:
sub do-something (:$verbose = True) { say $verbose; }
do-something; # True
do-something :verbose; # True
do-something :!verbose; # False
When written in term position but not as an argument of an argument list, it constructs a Pair object:
say (:!verbose); # verbose => False
Using a :verbose parameter would be a good way to set a Bool argument to True with a colon pair. It is equivalent to :verbose(True). :!verbose is just the negation of that, setting it to False, equivalent to :verbose(False).
#$ is a way of using the # prefix to remove the container from a scalar variable with sigil $.
Consider:
my $x = (1, 2, 3);
.say for $x;
Output:
(1 2 3)
vs.
my $x = (1, 2, 3);
.say for #$x;
Output:
1
2
3
Most operators can be searched for directly. These two cases in particular are not individual operators, but cases of using symbols in combination. Those are a little more difficult gather conveniently, but the docs are improving every day.

Usage of Array of abstract types in Julia

I'm exploring Julia so I'm a newbie. Now I'm exploring its strongly typed features. What I'm realizing is that I can't see the usage of abstract types for arrays. Let me explain with an example:
Let's suppose that I would like to create a function which accepts arrays of reals, no matter its concrete type. I would use:
function f(x::Array{Real})
# do something
end
This function can be never called without raising a f has no method matching f(::Array{Float64,1})
I would like to call f([1,2,3]) or f([1.,2.,3.]) as long as the type of the element is Real.
I've read that you could promote or convert the array (p.eg f(convert(Array{Real}, [1, 2, 3])) or so) but I see that way really non-dynamic and tedious.
Is there any other alternative rather than getting rid of the strongly typed behaviour?
Thanks.
To expand upon the solution by #user3580870, you can also use a typealias to make the function definition a little more succinct:
typealias RealArray{T<:Real} Array{T}
f(x::RealArray) = "do something with $x"
And then you can use the typealias in anonymous functions, too:
g = (x::RealArray) -> "something else with $x"
Since there's been an updated since the orginal answer, the keyword typealias is gone so that the solution of #Matt B. would now be
const RealArray{T<:Real} = Array{T}
f(x::RealArray) = "do something with $x"
I'll just put this here for the sake of completeness ;)
You can do this explicitly using the <: subtype operator:
function f(x::Array)
return zero.(x)
end
function f(x::Array{<:Real})
return one.(x)
end
#show f([1, 2])
#show f([1.0, 2.0])
#show f([1im, 2im])
prints
f([1, 2]) = [1, 1]
f([1.0, 2.0]) = [1.0, 1.0]
f([1im, 2im]) = Complex{Int64}[0+0im, 0+0im]

Get variable whose value is the maximum in an array

If I have an array of variables in Ruby:
a = 4
b = 7
c = 1
array = [a, b, c]
How can I get access to the name of the variable that has the highest value? (In this example b) I want to retrieve a reference to the element with the highest value, to be able to later manipulate it:
b += 10
I tried array.max but that just returns the max value 7
When you build an array by writing array = [a, b, c], the spots in the array do not retain any kind of association with the variables named a, b, and c, so you there is no way to do exactly what you are talking about. Those variables can change without affecting the array.
You could change the way you are storing your data in order to make this possible, but without knowing what data you are storing it is hard to recommend a good way to do it. You could consider storing your data inside a hash instead of in loose variables and an array:
hash = { a: 4, b: 7, c: 1}
Ruby does not support passing objects by reference, which is essentially what you are trying to do. When you call array.max, you are passed a copy of the Fixnum 7, and assignment and modification will be applied to this copy.
That is, you can not store a reference to this Array element, and modify it later. You can modify the maximum value on the spot, however, using:
array[array.index(array.max)] = array.max + 10
#=> 17
array
#=> [4, 17, 1]
Note that when there are duplicate values in the Array, array.index(array.max) will return the index of the first one.
Storing the index for later use is not a solid solution, since, while Arrays in Ruby are ordered, the Array or its elements can be modified between the point you retrieve the index, and the point where you decide to change the corresponding value.
Another answer suggests there's a hack to mimic pass-by-reference behaviour, but in doing this, you're working against the intention of the language, and it could lead to a lot of pain down the line.
If you are trying to manipulate the maximum of three values, then, you are better off doing something like this:
array.max + 10 # or any other manipulation for that matter.
If you are asking what you are asking for academic purposes, then, you could use Ruby's Binding to inspect values of local variables.
a = 4
b = 7
c = 1
array = [a, b, c]
# Select variable whose value matches with maximum of three elements
# Variable's name as symbol is obtained by this process
var = binding.send(:local_variables).select do |i|
array.max.eql? binding.local_variable_get(i)
end.first
#=> :b
# Update value of variable using symbol representing its name
binding.local_variable_set(var, binding.local_variable_get(var) + 10)
puts b
#=> 17
You could also use Binding#eval to manipulate the variable, for e.g.:
binding.eval("#{var.to_s} += 10")
#=> 17
Note that we need to use var.to_s as var contains a symbol, and we need to convert it to string to get variable name string that can be used in eval.
You can use Array#index for this..
1.9.3-p484 :008 > max_elem = array.index(array.max)
=> 1
1.9.3-p484 :009 > array[max_elem] = array[max_elem] + 10
=> 11
1.9.3-p484 :010 > array
=> [4, 17, 1]
1.9.3-p484 :011 >

Perl array initialized incorrectly

Just starting with Perl, and I used the wrong pair of parentheses for this code example:
#arr = {"a", "b", "c"};
print "$_\n" foreach #arr;
I mean, I can of course see WHAT it does when I run it, but I don't understand WHY it does that. Shouldn't that simply fail with a syntax error?
You have accidentally created an anonymous hash, which is a hash that has no identifier and is accessed only by reference.
The array #arr is set to a single element which is a reference to that hash. Properly written it would look like this
use strict;
use warnings;
my #arr = (
{
a => "b",
c => undef,
}
);
print "$_\n" foreach #arr;
which is why you got the output
HASH(0x3fd36c)
(or something similar) because that is how Perl will represent a hash reference as a string.
If you want to experiment, then you can print the value of the first hash element by using $arr[0] as a hash reference (the array has only a single element at index zero) and accessing the value of the element with key a with print $arr[0]->{a}, "\n".
Note that, because hashes have to have a multiple of two values (a set of key/value pairs) the hash in your own code is implicitly expanded to four values by adding an undef to the end.
It is vital that you add use strict and use warnings to the top of every Perl program you write. In this case the latter would have raised the warning
Odd number of elements in anonymous hash
It can be surprising how few things are syntax errors in Perl. In this case, you've stumbled onto the syntax for creating an an anonymous hash reference: { LIST }. Perl doesn't require the use of parentheses (the () kind) when initializing an array1. Arrays hold ordered lists of scalar (single) values and references are scalars so perl happily initializes your array with that reference as the only element.
It's not what you wanted, but it's perfectly valid Perl.
The () override the precedence of the operators and thus changes the behavior of the expression. #a = (1, 2, 3) does what you'd expect, but #a = 1, 2, 3 means (#a = 1), 2, 3, so it only assigns 1 to #a.
{ LIST } is the hash constructor. It creates a hash, assigns the result of LIST to it, and returns a reference to it.
my $h = {"a", "b", "c", "d"};
say $h->{a}; # b
A list of one hash ref is just as legit as any other list, so no, it shouldn't be a syntax error.

Resources