class Scalar

A mostly transparent container used for indirections

class Scalar {}

A Scalar is an internal indirection which is for most purposes invisible during ordinary use of Perl 6. It is the default container type associated with the $ sigil. A literal Scalar may be placed around a literal value by enclosing the value in $(…). This notation will appear in the output of a .perl method in certain places where it is important to note the presence of Scalars.

When a value is assigned to a $-sigiled variable, the variable will actually bind to a Scalar, which in turn will bind to the value. When a Scalar is assigned to a $-sigiled variable, the value bound to by that Scalar will be bound to the Scalar which that variable was bound to (a new one will be created if necessary.)

In addition Scalars delegate all method calls to the value which they contain. As such, Scalars are for the most part invisible. There is, however, one important place where Scalars have a visible impact: a Scalar will shield its contents from flattening by most Perl 6 core list operations.

A $-sigiled variable may be bound directly to a value with no intermediate Scalar using the binding operator :=. You can tell if this has been done by examining the introspective pseudo-method .VAR:

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␤» 

This same thing happens when values are assigned to an element of an Array, however, Lists directly contain their values:

my @a = 123;
@a[0].^name.say;            # OUTPUT: «Int␤» 
@a[0].VAR.^name.say;        # OUTPUT: «Scalar␤» 
[123][0].^name.say;     # OUTPUT: «Int␤» 
[123][0].VAR.^name.say# OUTPUT: «Scalar␤» 
(123)[0].^name.say;     # OUTPUT: «Int␤» 
(123)[0].VAR.^name.say# OUTPUT: «Int␤» 

Array elements may be bound directly to values using := as well, however this is to be discouraged as it may lead to confusion. Doing so will break exact round-tripping of .perl output – since Arrays are assumed to place Scalars around each element, Scalars are not denoted with $ in the output of Array.perl.

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

Binding a Scalar to a $-sigiled variable replaces the existing Scalar in that variable, if any, with the given Scalar. That means more than one variable may refer to the same Scalar. Because the Scalar may be mutated, this makes it possible to alter the value of both variables by altering only one of them:

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

SSA-style constants bind directly to their value with no intervening Scalar, even when =/assignment is used. They may be forced to use a Scalar by assigning a $-sigiled variable to them, at which point, they behave entirely like $-sigiled variables.

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␤» 

Atomic Operations on Scalar

A Scalar can have its value changed using a hardware-supported atomic compare and swap operation. This is useful when implementing lock free data structures and algorithms. It may also be fetched and assigned to in an "atomic" fashion, which ensures appropriate memory barriering and prevents unwanted optimizations of memory accesses.

A Scalar that will be used with an atomic operation should always be explicitly initialized with a value before any atomic operations are performed upon it. This is to avoid races with lazy allocation and auto-vivification. For example:

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

Will work in principle since an Array consists of Scalar containers. However, the container is only bound into the array upon initial assignment. Therefore, there would be a race to do that binding. The Scalar atomic operations will never check for or do any such auto-vivification, so as to make such bugs much more evident (rather than only observed under stress).

Routines

atomic-assign

Defined as:

multi sub 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.

atomic-fetch

multi sub 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:

my $started = False;
start { atomic-assign($startedTrue}
until atomic-fetch($started{ }

Is certain to terminate, while in:

my $started = False;
start { atomic-assign($startedTrue}
until $started { }

It would be legal for a compiler to observe that $started is not updated in the loop, and so lift the read out of the loop, thus causing the program to never terminate.

cas

Defined as:

multi sub cas($target is rw$expected$value)
multi sub cas($target is rw&operation)

Performs an atomic compare and swap of the value in the Scalar $target. The first form has semantics like:

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

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 not sensible on value types.

For example:

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

Will reliably only ever print Master! one time, as only one of the threads will be successful in changing the Scalar from NOT_STARTED to STARTED.

The second form, taking a code object, will first do an atomic fetch of the current value and invoke the code object with it. It will then try to do an atomic compare and swap of the target, using the value passed to the code object as $expected and the result of the code object as $value. If this fails, it will read the latest value, and retry, until a CAS operation succeeds.

Therefore, an item could be added to the head of a linked list in a lock free manner as follows:

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;

This will reliably build up a linked list of 4000 items, with 4 nodes with each value ranging from 0 up to 999.

method of

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

Returns the type constraint of the container.

Example:

my Cool $x = 42;
say $x.VAR.of.^name;            # OUTPUT: «Cool» 

Operators

infix ⚛=

multi sub 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 sub 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:

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

Is certain to terminate, while in:

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

It would be legal for a compiler to observe that $started is not updated in the loop, and so lift the read out of the loop, thus causing the program to never terminate.

Type Graph

Type relations for Scalar
perl6-type-graph Scalar Scalar Any Any Scalar->Any Mu Mu Any->Mu

Stand-alone image: vector