Up to Main Index                         Up to Journal for September, 2023

                   JOURNAL FOR THURSDAY 7TH SEPTEMBER, 2023
______________________________________________________________________________

SUBJECT: On types of typing…
   DATE: Thu  7 Sep 21:18:08 BST 2023

September already, where did that come from? I have been slowly working on
making Mere a better programming language by add runtime error checking with
nice error messages. Due to a bit of a dilemma I ended up procrastinating for
a while, mulling over my options…

The thing is, Mere was originally a strongly typed language. It’s only been
since the rewrite that it became a dynamically typed language with strong type
checking. For example you can have an int ‘x’ and turn it into a uint ‘x’, but
you can’t add an int and a uint together. However, dynamic typing requires a
lot of runtime support which slows everything down.

Hence my procrastination. In basic terms, do I keep Mere dynamically typed and
slow or strongly typed and fast? There other features at play as well like
compile time static analysis and compile time optimizations.

To that end I’ve been experimenting to see what it would take to make Mere
once again a strongly typed language. So far I have added a new operator ‘?’
which can be read as ‘what is’ and is used to define a variable’s type:


     i ? int    // what is i ? it is an int!
    ia ? []int  // what is ia? it is an int array!
    im ? [int]  // what is im? it is an int map!


Do those comments make anyone else think of Sam Vimes reading “Where’s my
cow?” :) There is also the ‘?=’ operator for type inference:


     j ?= 1                      // j  is the inferred int type
    ja ?= []int 1 2 3            // ja is the inferred int array type
    jm ?= [int] 1 "one" 2 "two"  // jm is the inferred int map type


The format is quite flexible: “x ? int”, “x?int” and “x ?int” all work.

If you’re wondering why the question mark, it was that or the commercial at
‘@’ or some Unicode symbol people complain about and say they can’t type. All
the other symbols were used and I needed something easy for experimenting. I
was going to use the colon, but there were too many issues with label usage
and untangling that wasn’t going to be the quick I was looking for.

Function parameter types are working, return types not so much yes. This
works, but the return type is currently being ignored:


    add: func a?int b?int
      return a+b
    endfunc ?int


A small, complete example:


    >cat -n strict.mr
         1	x ?= 3
         2	y ?= 5
         3	//(x?int, y?int) >< 3, 5
         4	println call add x y
         5
         6	add: func a?int, b?int
         7	  return a+b
         8	endfunc ?int
    >mere strict.mr
    8
    >


If I change line 1 to “x ?= 3u” and make ‘x’ a uint, then run the code again:


    >mere strict.mr
    testdata/test.mr:6: invalid type for parameter 2 on call,
                        have: uint want: int
    testdata/test.mr:7: operator "+" does not match signature iu
    >


While I’m experimenting, the errors are currently runtime checks — but they
will eventually be compile time errors. So far I’ve just been playing with the
int and uint data types, but it seems to be working out well and performance
is good.

The main issue I’m struggling with at the moment are maps. Maps always seem to
be the fly in the ointment. For example, should these two chunks of code be
allowed:


    im ?= [int] 1 "a"
    im[1] = 2u         // change int element to uint?


    range k; v; [int] 1 1, 2 2u
      x ?= v           // x would need to be re-definable
      println type x
    next


I don’t think “im[1] = 2u” should be allowed, simply because of the way Mere
uses maps as a poor man’s object. The range-next loop is more of an issue. I
could introduce an ‘any’, which then puts runtime checking back on table. Of
course you could then use ‘any’ to make “im[1] = 2u” work as well:


    im ?= [int] 1 any "a"
    im[1] = 2u


    x ? any
    range k; v; [int] 1 1, 2 2u
      x = v
      println type x
    next


Another alternative might be to make ‘v’ in the range-next loop take on the
type of the element regardless. Then you could look at the type of ‘v’ to
decide how to handle it:


    range k; v; [int] 1 1, 2 2u
      if type v == "int"
        i ? int = v
        println literal i
      elif type v == "uint"
        u ? uint = v
        println literal u
      fi
    next


And that ends up looking a bit of a mess really…

I’m still experimenting and playing with ideas. Your comments, suggestions and
ideas are welcome as always: diddymus@wolfmud.org

--
Diddymus


  Up to Main Index                         Up to Journal for September, 2023