Perl-Apollo/Corinna

Type System

Closed this issue · 9 comments

Ovid commented

Use this ticket to leave feedback for the Type System document.

Don't forget unsigned integers. In most languages it's tricky to force them if needed e.g. for bit fiddeling.

In current Perl 5 (AFAIK 5.10 to 5.32) it needs the following:

### get the width of an integer in bits without loading the heavy Config.pm.
our $width = int 0.999+log(~0)/log(2);

use integer;
no warnings 'portable'; # for 0xffffffffffffffff

Another consideration is structural vs. nominal typing.

In a nominal type system (using Raku notation, because I'm familiar with it), you cannot assign [1, 2, 3] to a parameter declared Int @a, because [1, 2, 3] is just Array, not Array[Int]`.

On the other hand, in a nominal type system, you can declare class UUID is Str { ... } and class PersonName is Str { ... }, and that prevents you from accidentally assigning a name to a UUID and vice versa, even though structurally they are both stored as strings.

TypeScript has had great success adding structural, compile-time only types to Javascript, which indicates it might be a good fit for retrofitting a type system onto a previously "untyped" language; but TBH I'm not familiar enough with that to judge if Perl 7+ could copy that approach.

(I'm leaving separate comments for separate pieces of feedback on the wiki page, hope that simplifies things compared to one big comment blob)

Regarding generics: I could totally live with a first version of a type system that doesn't handle generics at all, though I guess people will compare that to what Moose supports now, and loudly complain.

Coming up with a good type system that works with generics tends to be really hard though (just look at Java, Go, C++), so another option would be to cheat like Go does, and allow generics for built-in types only (Array[Int], Hash[Point]). Given the prevalence of arrays and hashes in Perl code, this could be acceptable 80/20 solution.

Thinking more about what classes of bugs a type system can prevent, there's one that annoys me at least once per week that Perl currently gets wrong and every[tm] other language gets right (I'm sure somebody will point out TCL now...):

Producing correct JSON is way too hard right now in Perl.

JSON distinguishes integers, floats, strings and booleans, and for Perl those are all just scalars. At work we use json schema to validate messages exchanged between services, and that makes me acutely aware of every time a Perl service produces something unexpected.

The two most common pitfalls for me are:

  • Strings vs. integer: it's far too easy to accidentally produce a string when the consumer expects and integer
  • integer vs float/"number": if the consumer expects a float, but your user entered a number that happened to be an integer as well, there just doesn't seem to be a sane way to force the likes of JSON::XS to produce a 0.0 instead of 0. There are cases where float is clearly the more appropriate data type (like, voltage readings from sensors), but once in a blue moon the value happen to come out as identical to an integer.

Not having proper booleans is also annoying, though manageable through explicit JSON::XS::true conversions or using the ´\0and\1` hack.

I don't know if this is in scope for the Cor type system to fix, but I sure hope something fixes it eventually :-)

On the other hand, in a nominal type system, you can declare class UUID is Str { ... } and class PersonName is Str { ... }, and that prevents you from accidentally assigning a name to a UUID and vice versa, even though structurally they are both stored as strings.

Good examples. In text or language processing I typically define (via Unicode properties):

  • PersonName (or GeoNames, Taxons etc.)
  • Abbreviations
  • Acronyms
  • Array of Graphemes (\X)
  • LanguageWord
  • etc.
Ovid commented

@moritz wrote:

Producing correct JSON is way too hard right now in Perl.

This is an old, old problem. I have had to deal with too much hell in the past from SOAP getting types wrong, too. Basically, if Perl has to interoperate with another system where "type" information is conveyed, it's a nightmare. SOAP, JSON, XML, and so on. It makes Perl look buggy and error-prone (because both are true in this context) to those who interoperate with the language.

One thing that :isa(*) does which leaving if off doesn’t is fix the type of what’s stored in the variable, so the compiler and/or runtime can catch any later attempt to assign something that isn’t a bike to it. I think that makes it worth including.

I think adding a type system to Perl is worth a separate parallel process. It would be nice to add type signatures to perl functions and methods in general (with a later enhancement to enable static type checking in lexical scope via a pragma).

Ovid commented

Closing this because it's out of scope of V1 and impacts far more than just Corinna.