Up to Main Index Up to Journal for November, 2023 JOURNAL FOR SATURDAY 4TH NOVEMBER, 2023 ______________________________________________________________________________ SUBJECT: The type operator is too “magical”? :( DATE: Sat 4 Nov 18:55:10 GMT 2023 November is here, along with the cold, wet, windy weather. Still, it will soon be time for the holiday season for everybody… I think I have nearly finished work on adding the ‘any’ type to Mere. Although a few people have called me out for getting too “magical” again. This is due to the type operator reporting the inner type of a variable of type any. For example: a := any 1 println type a // displays "int" and not "any" The argument is that type should always return the type of the variable, in this case “any”, and that the type any breaks that. I tend to agree. The question then becomes, if you have a variable of type any how do you get to the inner type? Normally you would use a conversion: a := any 1 i := int a // conversion to int In this case we know the inner type is an int. But what if you don’t know what the inner type is? For this I’ve added a “not any” operator ‘!any’ that reverses an any conversion: a := any 1 i := !any a // 'i' is now of type int The type operator can now be non-magical and return “any” for a variable of type any, then the type of the result, the inner value, can be checked: a := any 1 println type a // displays "any" println type !any a // displays "int" Where might this be useful? Consider a function that should accept any array or map as a parameter: > cat test.mr call fn1 []int 1 2 3 call fn1 [int] 1 "one", 2 "two", 3 "three" call fn1 "Test!" fn1: func a:any A := !any a // unwrap 'a' as 'A' t := type A // get unwrapped type if t[0] != "[" printf "fn1: a is %s not an array or map.\n" t return fi range k; v; A println k ": " v next endfunc > mere test.mr 0: 1 1: 2 2: 3 1: one 2: two 3: three fn1: a is string not an array or map. > Another example requires revisiting an earlier post of mine[1], with some heavy rewriting and a touch of regular expressions just for good measure: call add 1 2 call add "a" "b" call add 1 "a" call add true false add: func A:any B:any a := !any A b := !any B if (Ta := type a) != type b println "Cannot add A and B, different types." elif Ta ~m `^(int|uint|float|string)$` println a + b else println "Cannot add A and B, not numbers or strings." fi endfunc Here the function is trying to add together two numbers or strings. When run it produces: 3 ab Cannot add A and B, different types. Cannot add A and B, not numbers or strings. Exactly how I’d validate that code with the static checker I’m not sure… Another small fix I’ve made is related to labels. Currently any labels are displayed as a bare int value in traces, dumps and from the literal built-in. This can be confusing, they look just like an int. The fix I’ve made displays labels as ‘label(…)’. This is in-line with how ‘regexp(…)’ and ‘any(…)’ values are displayed: dummy: println literal dummy // displays "label(3)" And now it's on to the boring task of updating the documentation for the new ‘any’ type and ‘!any’ operator… *sigh* -- Diddymus [1] The journal “Boxing and unboxing variables”: ../10/21.html Up to Main Index Up to Journal for November, 2023