class Scalar

A mostly transparent container used for indirections
class Scalar {}

A Scalar is an internal indirection, that is, a way to refer indirectly to a value, which is, for most purposes, invisible during ordinary use of Raku. It is the default container type associated with the $ sigil. A literal Scalar may be placed around any literal by enclosing the value in $(ā€¦). This notation will appear in the output of a .raku 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 container will shield its content from flattening by most Raku core list operations.

say |(1,2,$(3,4));       # OUTPUT: Ā«12(3 4)ā¤Ā»

These Scalar containers can also be created on the fly by assigning to an anonymous scalar variable:

say |(1,2, $ = (3,4)); # OUTPUT: Ā«12(3 4)ā¤Ā»

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 output of 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 = 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ā¤Ā»

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

[1, $(2, 3)].raku.say;     # OUTPUT: Ā«[1, (2, 3)]ā¤Ā»
    (1, $(2, 3)).raku.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ā¤Ā»

Raku allows the use of constants with a static single assignment (SSA) style which bind directly to their value with no intervening Scalar container, 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).

Introspection

method of

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

Returns the type constraint of the container.

Example:

my Cool $x = 42;
    say $x.VAR.of;                  # OUTPUT: Ā«(Cool)ā¤Ā»

method default

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

Returns the default value associated with the container.

Example:

my $x is default(666) = 42;
    say $x.VAR.default;             # OUTPUT: Ā«666ā¤Ā»

method name

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

Returns the name associated with the container.

Example:

my $x = 42;
    say $x.VAR.name;                # OUTPUT: Ā«$xā¤Ā»

method dynamic

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

It will return False for scalars.

Example:

my $*FOO = 42;
    say $*FOO.VAR.dynamic;          # OUTPUT: Ā«Trueā¤Ā»

Note that you have to use the VAR method in order to get that information.

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)

Routines

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:

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

Is certain to terminate, while in:

my $started = False;
    start { atomic-assign($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.

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:

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($master, NOT_STARTED, STARTED) === NOT_STARTED {
            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.

Note: Before Rakudo version 2020.12, $target, expected and value had an Any type constraint.

Operators

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:

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.

See Also

class int

Native integer

class Allomorph

Dual value number and string

class Any

Thing/object

class AST

Abstract representation of a piece of source code

class atomicint

Integer (native storage at the platform's atomic operation size)

class Block

Code object with its own lexical scope

class CallFrame

Captures the current frame state

class Code

Code object

class Collation

Encapsulates instructions about how strings should be sorted

class Compiler

Information related to the compiler that is being used

class Complex

Complex number

class ComplexStr

Dual value complex number and string

class Cool

Object that can be treated as both a string and number

class CurrentThreadScheduler

Scheduler that synchronously executes code on the current thread

class Date

Calendar date

class DateTime

Calendar date with time

class Distribution::Hash

Distribution::Hash

class Distribution::Locally

Distribution::Locally

class Distribution::Path

Distribution::Path

class Distribution::Resource

Every one of the resources installed with a distribution

class Duration

Length of time

class Encoding::Registry

Management of available encodings

class FatRat

Rational number (arbitrary-precision)

class ForeignCode

Rakudo-specific class that wraps around code in other languages (generally NQP)

class Format

Convert values to a string given a format specification

class Formatter

Produce Callable for given format specification

class HyperSeq

An object for performing batches of work in parallel with ordered output

class HyperWhatever

Placeholder for multiple unspecified values/arguments

class Instant

Specific moment in time

class Int

Integer (arbitrary-precision)

class IntStr

Dual value integer and string

class Junction

Logical superposition of values

class Label

Tagged location in the source code

class Lock::Async

A non-blocking, non-re-entrant, mutual exclusion lock

class Macro

Compile-time routine

class Method

Member function

class Mu

The root of the Raku type hierarchy.

class Nil

Absence of a value or a benign failure

class Num

Floating-point number

role Numeric

Number or object that can act as a number

class NumStr

Dual value floating-point number and string

class ObjAt

Unique identification for an object

class Parameter

Element of a Signature

class Perl

Perl related information

class Proxy

Item container with custom storage and retrieval

class RaceSeq

Performs batches of work in parallel without respecting original order.

class Raku

Raku related information

package RakuAST

Namespace for holding RakuAST related classes

class RakuAST::Doc::Block

Contains the information of a RakuDoc block

class RakuAST::Doc::Declarator

Contains the declarator docs of a RakuAST object

class RakuAST::Doc::Markup

Contains the information about RakuDoc markup

class RakuAST::Doc::Paragraph

Contains the information about a RakuDoc paragraph

class Rat

Rational number (limited-precision)

class RatStr

Dual value rational number and string

class Routine

Code object with its own lexical scope and return handling

class Routine::WrapHandle

Holds all information needed to unwrap a wrapped routine.

class Signature

Parameter list pattern

class Str

String of characters

class StrDistance

Contains the result of a string transformation.

class Sub

Subroutine

class Submethod

Member function that is not inherited by subclasses

class Telemetry

Collect performance state for analysis

class Telemetry::Instrument::Thread

Instrument for collecting Thread data

class Telemetry::Instrument::ThreadPool

Instrument for collecting ThreadPoolScheduler data

class Telemetry::Instrument::Usage

Instrument for collecting getrusage data

class Telemetry::Period

Performance data over a period

class Telemetry::Sampler

Telemetry instrument pod

Subset UInt

Unsigned integer (arbitrary-precision)

class ValueObjAt

Unique identification for value types

class Variable

Object representation of a variable for use in traits

class Version

Module version descriptor

class Whatever

Placeholder for the value of an unspecified argument

class WhateverCode

Code object constructed by Whatever-priming

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.