Rules / Types, classes & roles / basic

Scalar Reference

A mostly transparent container used for indirections

What it is #

Routines #

Signatures are reproduced from the documentation, including their declared return types. A routine listed here is part of the type's published interface; whether Raku++ implements it is a separate question, answered by the examples below.

method of #

method of(Scalar:D: --> Mu)

Returns Mu.

Returns the type constraint of the container. Example:

method default #

method default(Scalar:D: --> Str)

Returns Str.

Returns the default value associated with the container. Example:

method name #

method name(Scalar:D: --> Str)

Returns Str.

Returns the name associated with the container. Example:

method dynamic #

method dynamic(Scalar:D: --> Bool)

Returns Bool.

It will return False for scalars. Example: Note that you have to use the VAR method in order to get that information.

sub atomic-assign #

multi atomic-assign($target is rw, $value)

Performs an atomic assignment of $value into the Scalar $target. The atomic-assign routine ensures that any required barriers are performed such that the changed value will be "published" to other threads.

sub atomic-fetch #

multi atomic-fetch($target is rw)

Performs an atomic read of the value in the Scalar $target and returns the read value. Using this routine instead of simply using the variable ensures that the latest update to the variable from other threads will be seen, both by doing any required hardware barriers and also preventing the compiler from lifting reads. For example: Is certain to terminate, while in: It would be legal for a compiler to observe that $started is not updated in

sub cas #

multi cas(Mu $target is rw, Mu \expected, Mu \value)
multi cas(Mu $target is rw, &operation)

Performs an atomic compare and swap of the value in the Scalar $target. The first form has semantics like: Except it is performed as a single hardware-supported atomic instruction, as if all memory access to $target were blocked while it took place. Therefore it is safe to attempt the operation from multiple threads without any other synchronization. Since it is a reference comparison, this operation is usually

infix ⚛= #

multi infix:<⚛=>($target is rw, $value)

Performs an atomic assignment of $value into the Scalar $target. The ⚛= operator ensures that any required barriers are performed such that the changed value will be "published" to other threads.

prefix #

multi prefix:<⚛>($target is rw)

Performs an atomic read of the value in the Scalar $target and returns the read value. Using this operator instead of simply using the variable ensures that the latest update to the variable from other threads will be seen, both by doing any required hardware barriers and also preventing the compiler from lifting reads. For example: Is certain to terminate, while in: It would be legal for a compiler to observe that $started is not updated in

Examples, run three ways #

Every example below comes from the official documentation, together with the output that documentation asserts. Each was then executed by Rakudo and by Raku++ when this page was built. Where the three agree, one result is shown; where they do not, all three are — because which of them is wrong is exactly the information worth having.

1 all-differ · 9 no-output · 9 ok · 2 rakupp-differs

class Scalar {}

Not executed: the documentation states no expected output for this example.

say |(1,2,$(3,4));       # OUTPUT: «12(3 4)␤»
Output
12(3 4)

Documentation, Rakudo and Raku++ all agree.

say |(1,2, $ = (3,4)); # OUTPUT: «12(3 4)␤»
Output
12(3 4)

Documentation, Rakudo and Raku++ all agree.

my $a = 1;
$a.^name.say;     # OUTPUT: «Int␤»
$a.VAR.^name.say; # OUTPUT: «Scalar␤»
my $b := 1;
$b.^name.say;     # OUTPUT: «Int␤»
$b.VAR.^name.say; # OUTPUT: «Int␤»
Documentation
Int
Scalar
Int
Int
Rakudo
Int
Scalar
Int
Int
Raku++
Int
Scalar
Int
Scalar

Raku++ disagrees with both the documentation and Rakudo — a defect.

my @a = 1, 2, 3;
@a[0].^name.say;            # OUTPUT: «Int␤»
@a[0].VAR.^name.say;        # OUTPUT: «Scalar␤»
[1, 2, 3][0].^name.say;     # OUTPUT: «Int␤»
[1, 2, 3][0].VAR.^name.say; # OUTPUT: «Scalar␤»
(1, 2, 3)[0].^name.say;     # OUTPUT: «Int␤»
(1, 2, 3)[0].VAR.^name.say; # OUTPUT: «Int␤»
Documentation
Int
Scalar
Int
Scalar
Int
Int
Rakudo
Int
Scalar
Int
Scalar
Int
Int
Raku++
Int
Int
Int
Int
Int
Int

Raku++ disagrees with both the documentation and Rakudo — a defect.

[1, $(2, 3)].raku.say;     # OUTPUT: «[1, (2, 3)]␤»
(1, $(2, 3)).raku.say;     # OUTPUT: «(1, $(2, 3))␤»
Output
[1, (2, 3)]
(1, $(2, 3))

Documentation, Rakudo and Raku++ all agree.

my $a = 1;
my $b := $a;
$b = 2;
$a.say;       # OUTPUT: «2␤»
Output
2

Documentation, Rakudo and Raku++ all agree.

my \c = 1;
c.^name.say;             # OUTPUT: «Int␤»
c.VAR.^name.say;         # OUTPUT: «Int␤»
my $a = 1;
my \d = $a;              # just "my \d = $ = 1" works, too
d.^name.say;             # OUTPUT: «Int␤»
d.VAR.^name.say;         # OUTPUT: «Scalar␤»
d = 2;                   # ok
c = 2;                   # fails
CATCH { default { put .^name, ': ', .Str } };
# OUTPUT: «X::Assignment::RO: Cannot modify an immutable Int␤»
Documentation
Int
Int
Int
Scalar
X::Assignment::RO: Cannot modify an immutable Int
Rakudo
Int
Int
Int
Scalar
X::Assignment::RO: Cannot modify an immutable Int (1)
Raku++
Int
Int
Int
Int

All three differ. Needs a human.

Not yet examined. Which of these is correct has not been established — do not treat either engine as settled here.

cas(@a[5], $expected, $value)

Not executed: the documentation states no expected output for this example.

my Cool $x = 42;
say $x.VAR.of;                  # OUTPUT: «(Cool)␤»
Output
(Cool)

Documentation, Rakudo and Raku++ all agree.

my $x is default(666) = 42;
say $x.VAR.default;             # OUTPUT: «666␤»
Output
666

Documentation, Rakudo and Raku++ all agree.

my $x = 42;
say $x.VAR.name;                # OUTPUT: «$x␤»
Output
$x

Documentation, Rakudo and Raku++ all agree.

my $*FOO = 42;
say $*FOO.VAR.dynamic;          # OUTPUT: «True␤»
Output
True

Documentation, Rakudo and Raku++ all agree.

my $s is dynamic = [1, 2, 3];
say $s.dynamic;                          # OUTPUT: «False␤»  (wrong, don't do this)
say $s.VAR.dynamic;                      # OUTPUT: «True␤»   (correct approach)
Output
False
True

Documentation, Rakudo and Raku++ all agree.

my $started = False;
start { atomic-assign($started, True) }
until atomic-fetch($started) { }

Not executed: the documentation states no expected output for this example.

my $started = False;
start { atomic-assign($started, True) }
until $started { }

Not executed: the documentation states no expected output for this example.

my $seen = $target;
if $seen<> =:= $expected<> {
$target = $value;
}
return $seen;

Not executed: the documentation states no expected output for this example.

constant NOT_STARTED = Any.new;
constant STARTED = Any.new;
my $master = NOT_STARTED;
await start {
    if cas($master, NOT_STARTED, STARTED) === NOT_STARTED {
        say "Master!"
    }
} xx 4

Not executed: the documentation states no expected output for this example.

class Node {
    has $.value;
    has Node $.next;
}
my Node $head = Node;
await start {
    for ^1000 -> $value {
        cas $head, -> $next { Node.new(:$value, :$next) }
    }
} xx 4;

Not executed: the documentation states no expected output for this example.

my $started = False;
start { $started ⚛= True }
until ⚛$started { }

Not executed: the documentation states no expected output for this example.

my $started = False;
start { $started ⚛= True }
until $started { }

Not executed: the documentation states no expected output for this example.