NAME

Confold - the <: compile time constant operator

VERSION

Version 0.02

SYNOPSIS

use Confold;

my $x = <: 42;         # folded at compile time
my $y = <: "hello";    # folded at compile time
my $z = <: $variable;  # runtime: creates immutable copy

DESCRIPTION

Introduces the <: prefix operator, which marks an expression as a compile-time constant. When the operand is a literal value, the operator is folded away entirely at compile time, leaving a plain constant with no runtime overhead at all. For non-constant operands, a runtime path creates an immutable copy.

The operator exists to say something to the compiler that a function call cannot. By the time an ordinary subroutine call has been built, the expression is wrapped in an entersub and every call checker and optimisation pass downstream has lost sight of what it contains. <: is visible earlier, so a value marked with it can still be recognised as simple.

my $a = <: 42;      # compiles to: my $a = 42;

The immutable copy is the same promise enforced at run time. Perl aliases @_ to the caller's variables, so an ordinary argument can be modified by the subroutine it is passed to; an argument marked with <: cannot.

sub clobber { $_[0] = "changed" }

my $open = "original";
clobber($open);            # $open is now "changed"

my $shut = "original";
clobber(<: $shut);         # dies: Modification of a read-only value

Compile-time variables

A variable declared with <: has a value the compiler can read:

my $slot = <: 'age:Int';

Perl cannot normally do this. A my variable is not populated until run time, so anything running while the program is still being compiled sees nothing there. That is why a class definition has to be repeated as a literal inside BEGIN, rather than named once and reused. With <: it does not:

use Object::Proto;

my $class = <: 'Person';
my $slot  = <: 'age:Int';

BEGIN { Object::Proto::define($class, $slot) }   # both are readable here

The value is passed on rather than the variable, both to subroutines and to anything inspecting the code as it compiles. So a module that examines its arguments during compilation - a call checker - sees an actual value and can act on it. Object::Proto uses this to settle a typed slot's check once instead of on every assignment:

my $age = <: 42;

Person::age($p, $age);      # the type check is resolved while compiling

Assigning to such a variable retires it: later reads go back to reading the variable, so they never return a value that has stopped being true. Because the value rather than the variable is passed, @_ aliasing cannot write through it, and a subroutine that assigns to $_[0] gets a read-only error.

What it does not do

<: folds an operand that is already constant. It does not evaluate arbitrary expressions at compile time, so it will not turn a function call into a constant, and it does not promote anything Perl had not already folded on its own. Its value is the marker and the immutable copy, not new folding.

Precedence

<: binds as tightly as \ and unary minus, so it takes the smallest term to its right rather than the whole expression:

<: $a + $b        # means: (<: $a) + $b
<: $a ** 2        # means: <: ($a ** 2)     - ** binds tighter
<: $h->{k} * 2    # means: (<: $h->{k}) * 2

Parenthesise when a whole expression is meant:

<: ($a + $b)

Scope

The operator is lexically scoped. It is active from use Confold to the end of the enclosing block or file, and no Confold switches it off again. Outside an active scope <: means whatever it meant before.

Limitations

Within an active scope, <: is claimed as the operator wherever a term is expected. A glob whose pattern begins with a colon, <:foo>, is therefore a syntax error rather than a glob. Write glob(":foo") instead. Everywhere an operator is expected instead of a term, < is untouched, so comparisons, <=>, left shift and readline all behave normally.

Quoted text is never affected. The operator is recognised during tokenisation of code only, so "a <: b", '<:encoding(UTF-8)', here-documents and regular expressions all keep their contents.

Loading Confold enables Perl's pluggable-operator path for the rest of the process. That is a compile-time cost only, and applies to any module using that hook; execution speed of code that does not use <: is unaffected.

SEE ALSO

Infix::Custom, for user-defined infix operators.

AUTHOR

LNATION <email@lnation.org>

LICENSE AND COPYRIGHT

This software is Copyright (c) 2026 by LNATION.

This is free software, licensed under the Artistic License 2.0.