$ raku -v
This is Rakudo version 2019.07.1 built on MoarVM version 2019.07.1
The following was done on Raku REPL. What am I doing wrong here? How do I assign values to CArray[WCHAR]?
I want $lpData[0] to be 0xABCD and $lpData[1] to be 0xEF12.
> use NativeCall;
Nil
> constant WCHAR := uint16;
(uint16)
> my $ValueData = 0xABCDEF12;
2882400018
> my CArray[WCHAR] $lpData;
(CArray[uint16])
> $lpData[ 0 ] = ( $ValueData +& 0xFFFF0000 ) +> 0x10;
Type check failed in assignment to $lpData; expected NativeCall::Types::CArray[uint16] but got Array ($[])
in block <unit> at <unknown file> line 1
> $lpData[ 1 ] = $ValueData +& 0x0000FFFF;
Type check failed in assignment to $lpData; expected NativeCall::Types::CArray[uint16] but got Array ($[])
in block <unit> at <unknown file> line 1
Many thanks,
-T
The problem is stated clearly in the error message: in the way you declare it, it's expecting every item to be a CArray[WCHAR]. Declare it this way, as is indicated in the documentation:
use NativeCall;
constant WCHAR = uint16; # No need to bind here also
my $native-array = CArray[WCHAR].new();
$native-array[0] = 0xABCDEF12 +& 0x0000FFFF;
say $native-array.list; # OUTPUT: «(-4334)»
CArray is not exactly a Positional, but it does have AT-POS defined so you can use square brackets to assign values. The error arises when, you try to assign to an non-initialized Scalar (which contains any) as if it were an array. The minimal change from your program is just initializing to a CArray[WCHAR]:
use NativeCall;
constant WCHAR = uint16; # No need to bind here also
my CArray[WCHAR] $native-array .= new;
$native-array[0] = 0xABCDEF12 +& 0x0000FFFF;
say $native-array.list; # OUTPUT: «(-4334)»
Related
I'd like to create an script which takes an input file and optionally an output file. When you don't pass an output file, the script uses the same filename as the input but with the extension changed. I don't know how to write a default parameter which changes the extension.
#!/usr/bin/env raku
unit sub MAIN(
Str $input where *.IO.f, #= input file
Str $output = $input.IO.extension("txt"), #= output file
Bool :$copy, #= copy file
Bool :$move, #= move file
);
Unfortunately that doesn't work:
No such method 'IO' for invocant of type 'VMNull'
in block <unit> at ./copy.raku line 5
How can I do something like that?
error message is less than awesome but program not working is expected because you have in the signature
Str $output = $input.IO.extension("txt")
but the right hand side returns an IO::Path object with that extension but $output is typed to be a String. That is an error:
>>> my Str $s := "file.csv".IO.extension("txt")
Type check failed in binding; expected Str but got IO::Path (IO::Path.new("file.t...)
in block <unit> at <unknown file> line 1
>>> sub fun(Str $inp, Str $out = $inp.IO.extension("txt")) { }
&fun
>>> fun "file.csv"
Type check failed in binding to parameter '$out'; expected Str but got IO::Path (IO::Path.new("file.t...)
in sub fun at <unknown file> line 1
in block <unit> at <unknown file> line 1
Sometimes compiler detects incompatible default values:
>>> sub yes(Str $s = 3) { }
===SORRY!=== Error while compiling:
Default value '3' will never bind to a parameter of type Str
------> sub yes(Str $s = 3⏏) { }
expecting any of:
constraint
but what you have is far from a literal, so runtime detection.
To fix it, you can either
change to Str() $output = $inp.IO.extension("txt") where Str() means "accept Any object and then cast it to Str". So $output will end up being a string like "file.txt" available in MAIN.
similar alternative: Str $output = $inp.IO.extension("txt").Str but it's repetitive in Str.
change to IO::Path() $output = $inp.IO.extension("txt"). Similarly, this casts to whatever recieved to an IO::Path object, so, e.g., you'll have "file.txt".IO available in $output. If you do this, you might want to do the same for $input as well for consistency. Since IO::Path objects are idempotent to .IO (in eqv sense), no other part of the code needs changing.
In Raku a scalar might be immutable or it might be an actual variable:
my $a := 6; # constant
my $b = 6; # variable
Is there a programmatic way to check whether a scalar is immutable without just trying to change it and seeing if it works?
First, a slight terminological correction (not to be nitpicky, but just because this area is a bit tricky and being precise with our terms can help).
It's not really right to say that my $a := 6 is a constant; that expression binds $a to the value 6, which prevents you from assigning a different value to $a (with the = operator). However, you can still rebind a new value to $a (with the := operator). This means that $a can still, in a sense, be mutated – or, at least, can be made to point to something new. For a truly constant $a, you should use either constant $a or change $a to a sigil-less variable (my \a = 6).
Now to the actual answer to your question: To determine whether $a is bound or assigned to a value, you can use $a.VAR.WHAT. If $a is assigned a value, this will return the type of container, (Scalar); if it is bound, then it will return the type of the bound value.
As far as I know, there isn't a way to tell the difference between an $a bound to a value and one that's a constant, though I would love to be wrong about that.
The code below illustrates what I just said:
my $a = 1;
say $a.VAR.WHAT; # OUTPUT: «(Scalar)»
$a = 2;
say $a; # OUTPUT: «2»
my $b := 1;
say $b.VAR.WHAT;# OUTPUT: «(Int)»
$b := 2;
say $b; # OUTPUT: «2»
constant $c = 1;
say $c.VAR.WHAT; # OUTPUT: «(Int)»
# $c := 2; ILLEGAL
say $c; # OUTPUT: «1»
Another way, using multiple dispatch:
my $a := 6; # constant
my $b = 6; # variable
multi sub mutable($ is rw) { True }
multi sub mutable($) { False }
say mutable($a); # False
say mutable($b); # True
say mutable(42); # False
After reading the Raku documentation, I only found this for undefining a variable. I believe that in Raku there are differences between assignment and binding.
Defining and undefining a scalar is easy.
> my $n
(Any)
> $n.defined
False
> $n = 3
3
> $n.defined
True
> $n = Nil
(Any)
> $n.defined
False
When the variable is binded, it's not possible.
> my $k := 5
5
> $k := Nil
===SORRY!=== Error while compiling:
Cannot use bind operator with this left-hand side
at line 2
------> <BOL>⏏<EOL>
> $k = Nil
Cannot assign to an immutable value
in block <unit> at <unknown file> line 1
For arrays or hashes, I can empty it, but the variable is still defined.
For functions, when you define a function with sub, you cannot undefine it, but you can with an anonymous function.
> my &pera = -> $n { $n + 2}
-> $n { #`(Block|140640519305672) ... }
> &pera = Nil
(Callable)
> &pera.defined
False
> my &pera = -> $n { $n + 2}
-> $n { #`(Block|140640519305672) ... }
> &pera = Nil
(Callable)
> &pera.defined
False
> sub foo ($n) { $n + 1}
&foo
> &foo.defined
True
> &foo = Nil
Cannot modify an immutable Sub (&foo)
in block <unit> at <unknown file> line 1
So what's the difference between assignment and binding?
How can I undefine a variable?
Lots of different issues to discuss here.
> my $k := 5;
> $k := Nil;
Cannot use bind operator
This first problem is the Raku REPL. cf your last SO. Have you tried CommaIDE or repl.it?
Your code is perfectly valid:
my $k := 5;
$k := Nil;
say $k; # Nil
Moving on:
my $k := 5;
$k = Nil;
Cannot assign to an immutable value
This is different. After binding 5 to $k, the $k = Nil code is attempting to assign a value into a number. Only containers[1] support assignment. A number isn't a container, so you can't assign into it.
Clarifying some cases you mentioned but didn't explicitly cover:
my #foo;
#foo := Nil;
Type check failed in binding; expected Positional...
While scalar variables (ones with a $ sigil) will bind to any value or container, an # sigil'd variable will only bind to a Positional container such as an Array. (Likewise a % to an Associative such as a Hash.)
Not only that, but these containers are always defined. So they still return True for .defined even if they're empty:
my #foo := Array.new; # An empty array
say #foo.elems; # 0 -- zero elements
say #foo.defined; # True -- despite array being empty
Now assigning Nil to an array:
my #foo;
#foo = Nil;
say #foo; # [(Any)]
If a declaration of an # sigil'd variable doesn't bind it to some explicit Positional type it is instead bound to the default choice for an # variable. Which is an Array with a default element value of Any.
The #foo = Nil; statement above assigns a Nil value into the first element of #foo. The assignment of a value into a non-existing element of a multi-element container means a new Scalar container pops into existence and is bound to that missing element before assignment continues. And then, because we're assigning a Nil, and because a Nil denotes an absence of a value, the Array's default value ((Any)) is copied into the Scalar instead of the Nil.
On to the sub case...
sub foo {}
&foo = {} # Cannot modify an immutable Sub (&foo)
&foo := {} # Cannot use bind operator ...
While a sub foo declaration generates an &foo identifier, it is deliberately neither assignable nor bindable. If you want a Callable variable, you must declare one using ordinary variable declaration.
Unbind or undefine a variable
You can't unbind variables in the sense of leaving them bound to nothing at all. (In other words, Raku avoids the billion dollar mistake.) In some cases you can rebind variables.
In some cases you can bind or assign an undefined value to a variable. If it's not a scalar variable then that's like the # variable example covered above. The scalar cases are considered next.
An example of the binding case:
my $foo := Any;
say $foo.defined; # False
say $foo; # (Any)
say $foo.VAR.WHAT; # (Any)
We'll see what the .VAR is about in a moment.
The assignment case:
my $foo = Any;
say $foo.defined; # False
say $foo.WHAT; # (Any)
say $foo.VAR.WHAT; # (Scalar)
It's important to understand that in this case the $foo is bound to a Scalar, which is a container, which is most definitely "defined", for some definition of "defined", despite appearances to the contrary in the say $foo.defined; line.
In the say $foo.WHAT; line the Scalar remains hidden. Instead we see an (Any). But the (Any) is the type of the value held inside the Scalar container bound to $foo.
In the next line we've begun to pierce the veil by calling .VAR.WHAT on $foo. The .VAR gets the Scalar to reveal itself, rather than yielding the value it contains. And so we see the type Scalar.
But if you call .defined on that Scalar it still insists on hiding!:
my $foo;
say $foo.VAR.defined; # False
say $foo.VAR.DEFINITE; # True
(The only way to force Raku to tell you the ultimate truth about its view of definiteness is to call the ultimate arbiter of definiteness, .DEFINITE.)
So what are the rules?
The compiler will let you assign or bind a given new value or container to a variable, if doing so is valid according to the original variable declaration.
Assigning or binding an undefined value follows the same rules.
Binding
All variables must be bound by the end of their declaration.
If a variable's declaration allows an undefined value to be bound/assigned to that variable, then the variable can be undefined in that sense. But in all other circumstances and senses variables themselves can never be "unbound" or "undefined".
Binding is about making a variable correspond to some container or value:
Variables with # and % sigils must be bound to a container (default Array and Hash respectively).
Variables with the $ sigil must be bound to either a container (default Scalar) or a value.
Variables with the & sigil must be bound to a Callable value or a Scalar constrained to contain a Callable value. (The & sigil'd variable that's visible as a consequence of declaring a sub does not allow rebinding or assignment.)
Assignment
Assignment means copying a value into a container.
If a variable is bound to a container, then you can assign into it, provided the assignment is allowed by the compiler according to the original variable declaration.
If a variable is not bound to a container, then the compiler will reject an assignment to it.
Scalar variables
If you use a scalar container as if it were a value, then you get the value that's held inside the container.
Binding a value (defined or undefined) to a scalar variable will mean it will stop acting as a container. If you then try to assign to that variable it won't work. You'd need to rebind it back to a container.
Footnotes
[1] In this answer I've used the word "container" to refer to any value that can serve as a container for containing other values. For example, instances of Array, Hash, or Scalar.
Suppose I have the following code:
my constant #suits = <Clubs Hearts Spades Diamonds>;
my constant #values = 2..14;
class Card {
has $.suit;
has $.value;
# order is mnemonic of "$value of $suit", i.e. "3 of Clubs"
multi method new($value, $suit) {
return self.bless(:$suit, :$value);
}
}
It defines some suits and some values and what it means to be a card.
Now, to build a deck, I essentially need to take the cross product of the suits and the values and apply that to the constructor.
The naiive approach to do this, would of course be to just iterate with a loop:
my #deck = gather for #values X #suits -> ($v, $c) {
take Card.new($v, $c);
}
But this is Raku, we have a cross function that can take a function as an optional argument!, so of course I'm gonna do that!
my #deck = cross(#values, #suits, :with(Card.new));
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
... wait no.
What about this?
my #deck = cross(#values, #suits):with(Card.new);
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
Still nothing. Reference maybe?
my #deck = cross(#values, #suits):with(&Card.new);
# ===SORRY!=== Error while compiling D:\Code\Raku/.\example.raku
# Illegally post-declared type:
# Card used at line 36
I read somewhere I can turn a function into an infix operator with []
my #deck = cross(#values, #suits):with([Card.new]);
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
That also doesn't work.
If classes are supposed to just be modules, shouldn't I then be able to pass a function reference?
Also why is it saying 'with' is that's unexpected? If I'm intuiting this right, what it's actually complaining about is the type of the input, rather than the named argument.
The error message is indeed confusing.
The :with parameter expects a Callable. Card.new is not a Callable. If you write it as :with( { Card.new($^number, $^suit) } ), it appears to work.
Note that I did not use $^value, $^suit, because they order differently alphabetically, so would produce the values in the wrong order. See The ^ twigil for more information on that syntax.
The error is LTA, this makes it a little bit better.
To get back to your question: you can find the code object that corresponds to Card.new with ^find_method. However, that will not work, as Card.new actually expects 3 arguments: the invocant (aka self), $value and $suit. Whereas the cross function will only pass the value and the suit.
The title of your question is “How do I take a reference to new?”, but that is not really what you want to do.
Raku being Raku, you can actually get a reference to new.
my $ref = Card.^lookup('new');
You can't use it like you want to though.
$ref(2,'Clubs'); # ERROR
The problem is that methods take a class or instance as the first argument.
$ref(Card, 2,'Clubs');
You could use .assuming to add it in.
$ref .= assuming(Card);
$ref(2,'Clubs');
But that isn't really any better than creating a block lambda
$ref = { Card.new( |#_ ) }
$ref(2,'Clubs');
All of these work:
cross( #values, #suits ) :with({Card.new(|#_)}) # adverb outside
cross( #values, #suits, :with({Card.new(|#_)}) ) # inside at end
cross( :with({Card.new(|#_)}), #values, #suits ) # inside at beginning
#values X[&( {Card.new(|#_)} )] #suits # cross meta-op with fake infix op
do {
sub new-card ($value,$suit) { Card.new(:$value,:$suit) }
#values X[&new-card] #suits
}
do {
sub with ($value,$suit) { Card.new(:$value,:$suit) }
cross(#values,#suits):&with
}
I have a name which I'd like to give to a variable, in another string variable:
my $name = '$a'; or simply my $name = 'a'; How to make the variable and to use it? I mean something like this (but it doesn't work):
my $name = '$a';
my {$name} = 1; # Doesn't work
say $a; # should be 1
A more general case. I have a list of variable names, say my #names = '$aa' ... '$cc'; How to declare and use the variable, whose name will be e.g. #names[2]?
According to documentation the lexical pad (symbol table) is immutable after compile time. Also (according to the same docs) it means EVAL cannot be used to introduce lexical symbols into the surrounding scope.
I suggest you use package variables, instead of lexical variable as suggested in the comments.
However, a workaround is possible: You can create your own lexical pad at run time (for the module requiring) using for example require MODULE:
my $name = '$a';
spurt 'MySymbols.pm6', "unit module MySymbols; use v6; my $name = 1; say \"\\$name = $name\"";
use lib '.';
require MySymbols;
Output:
$a = 1
Lexical scopes are immutable, but the way you would do it is ::($name) or MY::($name).
my $a; # required or it will generate an error
my $name = '$a';
::($name) = 1;
say $a; # 1
MY::($name) = 2;
say $a; # 2
sub foo ($name,$value) { CALLER::MY::($name) = $value }
foo($name,3);
say $a; # 3