Type Systems
So someone tried to graft a new type system onto Perl (which by the by is a "closed, strong and statically typed language") with perhaps predictable results.
< mauke> also, 'my array @numbers' provides no additional
information over 'my @numbers'
< mauke> one of the examples in the documentation is 'my int $x;
# $x is undef', which is a type error
< mauke> (btw, how can your integers be 64 bits if they're tagged?)
< mauke> how can scalars store references if there is no 'ref' type?
< LeoNerd> An article that writes "strong typing" means "has a type
system the author likes". "weak typing" means "a type
system the author doesn't like"
< LeoNerd> I usually classify people's attempts to build "type
systems" (I hate the 't' word) around Perl into three
sometimes-contradictory reasons. 1) to make the compiler
reject obviously-bad programs, 2) to make the runtime
reject obviously-bad data, 3) to make the runtime
processing of correct programs and data take less time
< mauke> in any case the real value of a type system is in
letting the programmer define their own types
< LeoNerd> ^-- that
So the "integer or undef" thing can be defined in some type systems,
(deftype maybe-integer () '(or null (integer 0 *)))
(defun foo (n) (declare (maybe-integer n)) n)
(foo 42)
(foo nil)
(foo 'bar)
or otherwise there must be some default value, and then maybe some way to tell the "default value because never set" and "default value set by something" cases apart. A common trick here is to use some bits as flag values and the remainder for integer values, which means that you will have fewer than the full range of, say, 64-bit integers, as some bits are reserved (the "tagging" that was mentioned, above). Maybe the numbers zero and up can be used for a map distance, and negative values for other things:
(defconstant +UNPATHABLE+ -1)
(deftype not-negative () '(integer -1 *))
(defun bar (n)
(declare (not-negative n))
(if (eq n +UNPATHABLE+)
nil
n))
(bar 42)
(bar 0)
(bar -1)
(bar -2)
This is sort of where the "Microsoft boolean" came from, a boolean of the values 0, 1, -1; true, false, error. Groping towards Vedanta logic, they are: true, false, unreal.
Or you could have a struct with a boolean (has the integer been set?) and the 64-bit (or whatever) integer, but then you may have performance issues because there's a whole struct being slung around instead of an integer so maybe don't do that in a hot path? In addition to whatever overhead the LISP brings with it. Anyways you can usually just leave off the DECLARE and similar bits if the Common LISP type system is getting in the way, usually when you're prototyping something and do not know what needs to be what.
(defstruct flavor1
(n nil :type (or null fixnum)))
; -1 presumably is invalid or like whatever
(defstruct flavor2
(n -1 :type fixnum))
(defstruct flavor3
(n 0 :type fixnum)
(setp nil :type boolean))
(defun value (f)
(declare (flavor3 f))
(if (flavor3-setp f)
(flavor3-n f)
(error "no flavor")))
(value (make-flavor3))
References
Or should this be the pointers section? Or how can we strong type this without beraking the keybaord?
https://blogs.perl.org/users/leon_timmermans/2025/02/a-deep-dive-into-the-perl-type-systems.html