Coercion/type checking: manually reproduce Perl6 standards - raku

I have a Module AttrX::Mooish which implements some of attribute features of Moo/Moose frameworks (lazyness, trigger, etc.). I also wanted the module to be as transparent to the end user as possible meaning support for both private and public attributes. It works by replacing attribute's container with a Proxy and storing its value in external storage. It also means that all the type checking and coercion Perl6 was doing is now my responsibility. My target is to mimic the default behavior is much as possible. I.e. for the end user:
has MyClass #foo is mooish(...);
must work the same as it would without the trait applied. Unfortunately, the subject of type manipulations is so much complicated and ununified in the language core that the more problems I fix the more problems I get afterwards. For example:
my Str #a = <a b c>; my Str #b = [1,2,3]
Type check failed in assignment to #b; expected Str but got Int (1)
As expected.
my Str #a; say #a.WHAT
(Array[Str])
Sure.
my Array[Str] $a = ["a", "b", "c"];
Type check failed in assignment to $a; expected Array[Str] but got Array ($["a", "b", "c"])
Well....
my Array[Str] $a = <a b c>;
Type check failed in assignment to $a; expected Array[Str] but got List ($("a", "b", "c"))
Not even coercing List to Array!
No wonder that the final typecheck line in my trait code:
$coerced-value ~~ $attr.type
Fails here and there despite same values/types used in variable/attribute assignments work OK.
I have a question with no hope of getting any positive answer to it: is there a single entry point used by the assignment operator which does all the coerce/typecheck? Ideally I would simply:
$value = coerce($value, $type);
check-type($value, :type($attr.type), :name($attr.name))
I tried to trace down from the grammar, but haven't got enough spare time to complete this yet. Besides, it is mostly nqp which I don't know and can't really understand.
But since the existence of such entry point(s) is unlikely I would like to ask for any advises related to this area. Like, for example, SmokeMachine on #perl6 provided me with a great idea of obtaining base type of a parametrized type using .^parents method.
So far, the biggest problems are with:
To check if type is parametrized I can't use a single role or class to match against. So far the only approach I have is by finding if there is of method and testing its output. Unfortunately, if a class provides FALLBACK very unclear error message (the one about AUTOGEN) is produced. :no_fallback is desirable, but definite and subset types have their own find_method which doesn't support named parameters and I end up with another error message.
If a prepare type-related attributes ($!coerce-type) in compose method of my trait role applied to the Attribute object (where actually the attributes are declared) I find them later at run-time unitialized. Guessing its something related to compose time. But wanna be sure if nothing is missed here.
Is there any better way to perform type-check than $value ~~ $type?

[Comments indicate that this out-of-date question was supposed to be closed in 2020 but it never was. Here's a very brief answer in case someone comes across this.]
Sometime after asking this question, the asker significantly revised Raku's coercion mechanism. See Report on New Coercions. This new syntax for coercion is in the docs.
Using this new style, the following line from the question:
my Array[Str] $a = ["a", "b", "c"];
say $a;
# OUTPUT: Type check failed in assignment to $a;
# expected Array[Str] but got Array ($["a", "b", "c"])
becomes
my Array[Str]() $a = ["a", "b", "c"];
say $a;
# OUTPUT: [a b c]
(That is, Array[Str]() means "something that can be coerced into an Array of Strings". That's different from Array[Str()] ("an Array of things that can be coerced to Strings") and from Array[Str()]() ("something that can be coerced into an Array of things that can be coerced into Strings").)
Similarly, the following part of the question now has an answer:
is there a single entry point used by the assignment operator which does all the coerce/typecheck? Ideally I would simply [define how a type is coerced into my type]
With the new coercion protocol, the "single entry point" is the COERCE method, which users can define for their types to teach Raku how to coerce into those types.

Related

Deserializing tuples with argument in Rust

I am a beginner in rust and working with some api that returns bytes that I can deserialize by defining their types.
result: (f64, f64, f64) = api.call();
Can I do the same by dynamically by passing a value n for the number of elements?
All elements of the tuple are of the same type. I would like to do something like this:
result: tuple(f64, 3) = api.call();
Here is the API of the call function.
Edit:
In case anyone ever encounters that issue in the future. I could deserialize the output by adopting this solution.
For reference: call() returns a Result<D: Detokenize, _>. Detokenize is mainly implemented for all T that implement Tokenizable.
All types that can receive the result are listed here.
Note that additional to tuples of various size, it's also implemented for:
impl<T: TokenizableItem + Clone, const N: usize> Tokenizable for [T; N]
Further, note that it is an async function with a Result, meaning you have to await it and deal with the potential error.
So you should(tm) be able to write:
result: [f64; 3] = api.call().await.unwrap();
Of course in a real project I would advise to replace unwrap() with some proper error handling.
Disclaimer: I don't know how to use the rest of ethers-core, so I'm unable to verify this in a test project. This information is purely derived from the documentation.
Static vs dynamic size
[f64; 3] requires you to know the number of elements at compile time.
Note that another Tokenizable is Vec<T>, meaning you could also specify Vec<T> as a result type. The length of this one will then be resolved at runtime, depending on how many elements of T the api.call() returns.
Further background information
Note that there is no such thing as a tuple that has N number of T elements, because a tuple is not a repetition of one type, it's a collection of types. Every element of a tuple can have a different type.
If you want to represent a repetition of one type, an array is what you really want. It's defined as one type T repeated N times: [T; N].

Variable re-assign method result if not Nil

Is there idiomatic way of applying and assigning object variable method call, but only if it's defined (both method and the result)?
Like using safe call operator .? and defined-or operator //, and with "DRY principle" – using the variable only once in the operation?
Like this (but using another variable feels like cheating):
my $nicevariable = "fobar";
# key step
(my $x := $nicevariable) = $x.?possibly-nonexistent-meth // $x;
say $nicevariable; # => possibly-nonexistent-meth (non-Nil) result or "foobar"
... And avoiding andthen, if possible.
Are you aware of the default trait on variables?
Not sure if it fits your use case, but $some-var.?unknown-method returns Nil, so:
my $nicevariable is default("fobar");
$nicevariable = $nicevariable.?possibly-nonexistent-meth;
say $nicevariable; # fobar
results in $nicevariable being reset to its default value;
I'm not entirely sure what you mean by "using the variable only once in the operation". If Liz's answer qualifies, then it's probably the cleaner way to go.
If not, here's a different approach that avoids naming the variable twice:
my $nicevariable = "foobar";
$nicevariable.=&{.^lookup('possibly-nonexistent-meth')($_)}
This is a bit too cryptic for my tastes; here's what it does: If the method exists, then that's similar to¹ calling &method($nicevariable), which is the same as $nicevariable.method. If the method does not exist, then it's like calling Mu($nicevariable) – that is, coercing $nicevariable into Mu or a subtype of Mu. But since everything is already a subtype of Mu, that's a no-op and just returns $nicevariable.
[1]: Not quite, since &method would be a Sub, but basically.
EDIT:
Actually, that was over-complicating things. Here's a simpler version:
my $nicevariable = "foobar";
$nicevariable.=&{.?possibly-nonexistent-meth // $_}
Not sure why I didn't just have that to begin with…
Assuming the method returns something that is defined, you could do (if I'm understanding the question correctly):
my $x = "foobar";
$x = $_ with $y.?possibly-nonexistent-meth;
$x will remain unchanged if the method didn't exist (or it did exist and returned a type object).
As of this merge you can write:
try { let $foo .= bar }
This is a step short of what I think would have been an ideal solution, which is unfortunately a syntax error (due to a pervasive weakness in Raku's current grammar that I'm guessing is effectively unsolvable, much as I would love it to be solved):
{ let $foo .?= bar } # Malformed postfix call...
(Perhaps I'm imagining things, but I see a glimmer of hope that the above wrinkle (and many like it) will be smoothed over a few years from now. This would be after RakuAST lands for Raku .e, and the grammar gets a hoped for clean up in Raku .f or .g.)
Your question's title is:
Variable re-assign method result if not Nil
My solution does a variable re-assign method if not undefined, which is more general than just Nil.
Then again, your question's body asks for exactly that more general solution:
Is there idiomatic way of applying and assigning object variable method call, but only if it's defined (both method and the result)?
So is my solution an ideal one?
My solution is not idiomatic. But that might well be because of the bug I found, now solved with the merge linked at the start of my answer. I see no reason why it should not become idiomatic, once it's in shipping Rakudos.
The potentially big issue is that the try stores any exception thrown in $! rather than letting it blow up. Perhaps that's OK for a given use case; perhaps not.
Special thanks to you for asking your question, which prompted us to come up with various solutions, which led me to file an issue, which led vrurg to both analyse the problem I encountered and then fix it. :)

Mixing-in roles in traits apparently not working

This example is taken from roast, although it's been there for 8 years:
role doc { has $.doc is rw }
multi trait_mod:<is>(Variable $a, :$docced!) {
$a does doc.new(doc => $docced);
}
my $dog is docced('barks');
say $dog.VAR;
This returns Any, without any kind of role mixed in. There's apparently no way to get to the "doc" part, although the trait does not error. Any idea?
(This answer builds on #guifa's answer and JJ's comment.)
The idiom to use in variable traits is essentially $var.var.VAR.
While that sounds fun when said aloud it also seems crazy. It isn't, but it demands explanation at the very least and perhaps some sort of cognitive/syntactic relief.
Here's the brief version of how to make some sense of it:
$var makes sense as the name of the trait parameter because it's bound to a Variable, a compiler's-eye view of a variable.
.var is needed to access the user's-eye view of a variable given the compiler's-eye view.
If the variable is a Scalar then a .VAR is needed as well to get the variable rather than the value it contains. (It does no harm if it isn't a Scalar.)
Some relief?
I'll explain the above in more detail in a mo, but first, what about some relief?
Perhaps we could introduce a new Variable method that does .var.VAR. But imo this would be a mistake unless the name for the method is so good it essentially eliminates the need for the $var.var.VAR incantation explanation that follows in the next section of this answer.
But I doubt such a name exists. Every name I've come up with makes matters worse in some way. And even if we came up with the perfect name, it would still barely be worth it at best.
I was struck by the complexity of your original example. There's an is trait that calls a does trait. So perhaps there's call for a routine that abstracts both that complexity and the $var.var.VAR. But there are existing ways to reduce that double trait complexity anyway, eg:
role doc[$doc] { has $.doc is rw = $doc}
my $dog does doc['barks'];
say $dog.doc; # barks
A longer explanation of $var.var.VAR
But $v is already a variable. Why so many var and VARs?
Indeed. $v is bound to an instance of the Variable class. Isn't that enough?
No, because a Variable:
Is for storing metadata about a variable while it's being compiled. (Perhaps it should have been called Metadata-About-A-Variable-Being-Compiled? Just kidding. Variable looks nice in trait signatures and changing its name wouldn't stop us needing to use and explain the $var.var.VAR idiom anyway.)
Is not the droid we are looking for. We want a user's-eye view of the variable. One that's been declared and compiled and is then being used as part of user code. (For example, $dog in the line say $dog.... Even if it were BEGIN say $dog..., so it ran at compile-time, $dog would still refer to a symbol that's bound to a user's-eye view container or value. It would not refer to the Variable instance that's only the compiler's-eye view of data related to the variable.)
Makes life easier for the compiler and those writing traits. But it requires that a trait writer accesses the user's-eye view of the variable to access or alter the user's-eye view. The .var attribute of the Variable stores that user's-eye view. (I note the roast test has a .container attribute that you omitted. That's clearly now been renamed .var. My guess is that that's because a variable may be bound to an immutable value rather than a container so the name .container was considered misleading.)
So, how do we arrive at $var.var.VAR?
Let's start with a variant of your original code and then move forward. I'll switch from $dog to #dog and drop the .VAR from the say line:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a does role { has $.doc = $docced }
}
my #dog is docced('barks');
say #dog.doc; # No such method 'doc' for invocant of type 'Array'
This almost works. One tiny change and it works:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var does role { has $.doc = $docced }
}
my #dog is docced('barks');
say #dog.doc; # barks
All I've done is add a .var to the ... does role ... line. In your original, that line is modifying the compiler's-eye view of the variable, i.e. the Variable object bound to $a. It doesn't modify the user's-eye view of the variable, i.e. the Array bound to #dog.
As far as I know everything now works correctly for plural containers like arrays and hashes:
#dog[1] = 42;
say #dog; # [(Any) 42]
say #dog.doc; # barks
But when we try it with a Scalar variable:
my $dog is docced('barks');
we get:
Cannot use 'does' operator on a type object Any.
This is because the .var returns whatever it is that the user's-eye view variable usually returns. With an Array you get the Array. But with a Scalar you get the value the Scalar contains. (This is a fundamental aspect of P6. It works great but you have to know it in these sorts of scenarios.)
So to get this to appear to work again we have to add a couple .VAR's as well. For anything other than a Scalar a .VAR is a "no op" so it does no harm to cases other than a Scalar to add it:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var.VAR does role { has $.doc = $docced }
}
And now the Scalar case also appears to work:
my $dog is docced('barks');
say $dog.VAR.doc; # barks
(I've had to reintroduce the .VAR in the say line for the same reason I had to add it to the $a.var.VAR ... line.)
If all were well that would be the end of this answer.
A bug
But something is broken. If we'd attempted to initialize the Scalar variable:
my $dog is docced('barks') = 42;
we'd see:
Cannot assign to an immutable value
As #guifa noted, and I stumbled on a while back:
It seems that a Scalar with a mixin no longer successfully functions as a container and the assignment fails. This currently looks to me like a bug.
Not a satisfactory answer but maybe you can progress from it
role doc {
has $.doc is rw;
}
multi trait_mod:<is>(Variable:D $v, :$docced!) {
$v.var.VAR does doc;
$v.var.VAR.doc = $docced;
}
say $dog; # ↪︎ Scalar+{doc}.new(doc => "barks")
say $dog.doc;  # ↪︎ barks
$dog.doc = 'woofs'; #
say $dog; # ↪︎ Scalar+{doc}.new(doc => "woofs")
Unfortunately, there is something off with this, and applying the trait seems to cause the variable to become immutable.

How to die on undefined values?

I am attempting to work with a hash in Raku, but when I put some fake values into it (intentionally) like
say %key<fake_key>;
I get
(Any)
but I want the program to die in such occurrences, as Perl does, because this implies that important data is missing.
For example,
#!/usr/bin/env perl
use strict;
use warnings 'FATAL' => 'all';
use autodie ':all';
my %hash;
print "$hash{y}\n";
as of 5.26.1 produces
Use of uninitialized value $hash{"y"} in concatenation (.) or string at undefined.pl line 8.
Command exited with non-zero status 255
How can I get the equivalent of use warnings 'FATAL' => 'all' and use autodie qw(:all) in Raku?
Aiui your question is:
I'm looking for use autodie qw(:all) & use warnings 'FATAL' => 'all' in Raku
The equivalent of Perl's autodie in Raku
Aiui the equivalent of use autodie qw(:all) in Perl is use fatal; in Raku. This is a lexically scoped effect (at least it is in Raku).
The autodie section in the Perl-to-Raku nutshell guide explains that routines now return Failures to indicate errors.
The fatal pragma makes returning a Failure from a routine automatically throw an exception that contains the Failure. Unless you provide code that catches them, these exceptions that wrap Failures automatically die.
The equivalent of Perl's use warnings 'FATAL' in Raku
Aiui the equivalent of use warnings 'FATAL' => 'all' in Perl is CONTROL { when CX::Warn { note $_; exit 1 } } in Raku. This is a lexically scoped effect (at least it is in Raku).
CONTROL exceptions explains how these work.
CONTROL exceptions are a subset of all exceptions that are .resume'd by default -- the program stays alive by default when they're thrown.
The Raku code I've provided (which is lifted from How could I make all warnings fatal? which you linked to) instead makes CONTROL exceptions die (due to the exit routine).
Returning to your current question text:
say %key<fake_key>; # (Any)
I want the program to die in such occurrences ...
Use either Jonathan++'s answer (use put, which, unlike say, isn't trying to keep your program alive) or Scimon++'s KeyRequired answer which will make accessing of a non-existent key fatal.
... as Perl does ...
Only if you use use warnings 'FATAL' ..., just as Raku does if you use the equivalent.
... because this implies that important data is missing.
Often it implies unimportant data is missing, or even important data that you don't want defined some of the time you attempt to access it, so both Perls and Raku default to keeping your program alive and require that you tell it what you want if you want something different.
You can use the above constructs to get the precise result you want and they'll be limited to a given variable (if you use the KeyRequired role) or statement (using put instead of say) or lexical scope (using a pragma or the CONTROL block).
You can create a role to do this. A simple version would be :
role KeyRequired {
method AT-KEY( \key ) {
die "Key {key} not found" unless self.EXISTS-KEY(key);
nextsame;
}
};
Then you create your hash with : my %key does KeyRequired; and it will die if you request a non existent key.
The simple answer is to not use say.
say %key<fake_key>;
# (Any)
put %key<fake_key>;
# Use of uninitialized value of type Any in string context.
# Methods .^name, .perl, .gist, or .say can be used to stringify it to something
# meaningful.
# in block <unit> at <unknown file> line 1
say calls .gist which prints enough information for a human to understand what was printed.
put just tries to turn it into a Str and print that, but in this case it produces an error.
Perl 5 warns, not dies, in this case. Perl 6 will do the same if equivalent code is used:
my %key;
print "%key<fake_key>\n"; # Gives a warning
Or, more neatly, use put:
my %key;
put %key<fake_key>;
The put routine ("print using terminator") will stringify the value, which is what triggers the warning about use of an undefined value in string context.
By contrast, say does not stringify, but instead calls .gist on the object, and prints whatever it returns. In the case of an undefined value, the gist of it is the name of its type, wrapped in parentheses. In general, say - which uses .gist underneath - gives more information. For example, consider an array:
my #a = 1..5;
put #a; # 1 2 3 4 5
say #a; # [1 2 3 4 5]
Where put just joins the elements with spaces, but say represents the structure and that it's an array.

The use of ">>" in Pharo/Smalltalk

I am implementing futures in Pharo. I came across this website http://onsmalltalk.com/smalltalk-concurrency-playing-with-futures. I am following this example and trying to replicate it on Pharo. However, I get to this point the last step and I have no idea what ">>" means: This symbol is not also included as part of Smalltalk syntax in http://rigaux.org/language-study/syntax-across-languages-per-language/Smalltalk.html.
BlockClosure>>future
^ SFuture new value: self fixTemps
I can see future is not a variable or a method implemented by BlockClosure. What should I do with this part of the code to make the promises/futures work as indicated at http://onsmalltalk.com/smalltalk-concurrency-playing-with-futures? I cannot add it on the Playground or as a method to my Promise class as it is, or am I missing something?
After adding the future method to BlockClosure, this is the code I try on the PlayGround.
value1 := [200 timesRepeat:[Transcript show: '.']. 6] future.
value2 := [200 timesRepeat:[Transcript show: '+']. 6] future.
Transcript show: 'other work'.
Transcript show: (value1 + value2).
Date today
The transcript displays the below error instead of the expected value of 12.
UndefinedObject>>DoIt (value1 is Undeclared)
UndefinedObject>>DoIt (value2 is Undeclared)
For some reason that it would be nice to learn, there is a traditional notation in Smalltalk to refer to the method with selector, say, m in class C which is C>>m. For example, BlockClosure>>future denotes the method of BlockClosure with selector #future. Interestingly enough, the expression is not an evaluable Smalltalk one, meaning, it is not a Smalltalk expression. It is just a succinct way of saying, "what comes below is the source code of method m in class C". Just that.
In Smalltalk, however, methods are objects too. In fact, they are instances of CompiledMethod. This means that they can be retrieved by sending a message. In this case, the message is methodAt:. The receiver of the message is the class which implements the method and the argument is the selector (respectively, C and #m, or BlockClosure and #future in your example).
Most dialects, therefore, implement a synonym of methodAt: named >>. This is easily done in this way:
>> aSymbol
^self methodAt: aSymbol
This puts the Smalltalk syntax much closer to the traditional notation because now BlockClosure>>future looks like the expression that would send the message >> to BlockClosure with argument future. However, future is not a Symbol unless we prepend it with #, namely #future. So, if we prefix the selector with the # sign, we get the literal Symbol #future, which is a valid Smalltalk object. Now the expression
BlockClosure >> #future
becomes a message, and its result after evaluating it, the CompiledMethod with selector #future in the class BlockClosure.
In sum, BlockClosure>>future is a notation, not a valid Smalltalk expression. However, by tweaking it to be BlockClosure >> #future, it becomes an evaluable expression of the language that returns the method the notation referred to.