Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the meaning of (Any) in Raku - specifically the ()?

Tags:

raku

Here is an experiment with Raku:

> my $x
(Any)
> my $y=1
1
> my @a=[1, 2]
[1 2]
> my %h=a=>'b'
{a => b}
> say "nil" unless $x
nil

I can see that [] indicates an array literal, {} a hash literal.

I can also see that (Any) behaves like nil - returning false in the boolean context shown above.

I find the (Any) interesting. The documentation tells me that Any is just one of the god classes in Raku. But what do the parenthesis () around Any tell me?

like image 962
Ross Attrill Avatar asked May 15 '20 11:05

Ross Attrill


3 Answers

When you use the REPL, the result of the expression is shown using say. The say function calls the .gist function on the expression.

Any is a type-object. Type-objects have a .gist method that puts the parentheses around them.

The put function is almost the same as the say function, but it calls the .Str function on the expression. And that produces a warning, because you cannot really stringify a type object. Observe the difference:

$ raku -e 'say Any'
(Any)

# raku -e 'put Any'
Use of uninitialized value of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to something meaningful.
  in block <unit> at -e line 1

See Classes and Objects, Type System, Type Objects for more information.

like image 69
Elizabeth Mattijsen Avatar answered Oct 17 '22 16:10

Elizabeth Mattijsen


There is a very simple answer.

Any is a class. Specifically it is the default base class for every other class.

In Raku you can pass around a class the same way you can pass an instance.

my $a = 1;
my $b = $a.WHAT;

say $b;
# (Int)

The thing is if you try and use the class as if it were an instance, bad things will happen.

say $b + 4;
# ERROR: … must be an object instance of type 'Int', not a type object of type 'Int'.

When you use the REPL it automatically calls .gist and prints the result.

.gist is meant for humans to be able to understand what the value is.

So then why would it add parenthesis around the name of the class?

It makes sense to me that it does that to tell you it isn't a Str or some other instance.

say 'Str'; # say calls .gist
# Str

say 'abc'.WHAT;
# (Str)

say 'abc'.WHAT.^name;
# Str

say 'abc'.^name;
# Str

All but one of those is an instance of the Str class.
(Guess which one.)


Basically the parens tell you that it would be an error to try and use it as an instance.

like image 6
Brad Gilbert Avatar answered Oct 17 '22 15:10

Brad Gilbert


In addition to lizmat's excellent answer, it's probably relevant to explain what's going on here.

When you say my $foo, you're effectively saying my Any $foo.1 And when you say my @foo, you're implicitly saying something closer to my Any @foo which is the same as my Array[Any] $foo (but in a positional container). That lets you put anything into the array, because it's typed, well, as Any.

When you access an object that's undefined, it returns an undefined value — but that value is still typed. It just happens that by default, the type is Any. We could, however, change some things and it would probably become clearer:

my Str $foo;
say $foo;    # a Str that's undefined, so '(Str)';
my $bar;     # implicitly typed Any
say $bar;    # an Any that's undefined, so '(Any)';

my Int @foo = 0, 1, 2;
say @foo[0];   # an Int defined as 0, so '0'
say @foo[1];   # an Int defined as 1, so '1'
say @foo[3];   # an Int that's undefined, so '(Int)'

As lizmat pointed out in her answer, (Type) is the default representation of the .gist method, which is used by .say, for undefined values.2

The reason that they don't return Nil is because by definition, Nil returns Nil for every method that's called upon it (with a few exceptions like Bool where it returns False) — it's sort of like Objective-C's nil. But an undefined type object still has uses: for instance, you can still call methods on it, as long as they don't access attributes. There are some times where that can be a very useful property, and it's what actually enables you to do something like:

  my Foo $foo .= new;

Which is syntactical sugar for

  my Foo $foo;
  $foo = $foo.new;

$foo is a an undefined type object, so we actually still call Foo.new.


  1. As raiph rightly points out in the comments, I should have noted this isn't exactly what's going on, but from an end-user perspective, is close enough and much less complicated.
  2. One can always override this, and I've done that for some of my classes that have names suspiciously close to or identical to builtins that add a clear prefix so I don't get them mixed up.
like image 5
user0721090601 Avatar answered Oct 17 '22 15:10

user0721090601