The missing bit in DIP1000

Ola Fosheim Grøstad ola.fosheim.grostad at gmail.com
Thu Jun 23 08:56:49 UTC 2022


There are some reflections to be had with how DIP1000 changes the 
type system. I think this change is coming from not making the 
true type system explicit.

Imagine that all types come in two varieties: scope and heap. 
When we write

```d
   void f(int x){…}
```

the full type would be:

```d
   void f(scope(int) x){…}
```

If we now introduce «|» to mean union, so that the union type A 
and type B becomes «A|B» then we can think that when we write

```d
int* p;
```

the full type would be:

```d
(scope(int)|heap(int)|null)* p;
```

So in the context of DIP1000, when we write:


```d
   void f(int x){
     int* p = null;
     if (condition) p = &x;
     g(p);
     if (condition) p = null;
     else p = new int(5);
     g(p)
     }
```

the full typing ought to be:

```d
   void f(scope(int) x){
     (scope(int)|heap(int)|null)* p=null;  // *p narrowed to: null
     if (condition) p = &x;           // *p widened to: 
scope(int)|null
     g(p);                            // called as 
g((scope(int)|null)*)
     if (condition) p = null;
     else p = new int(5);             // *p becomes: heap(int)|null
     g(p);                            // called as 
g((heap(int)|null)*)
   }
```

This is basic flow typing and not too difficult to understand, it 
is also more versatile than DIP1000 as it can be used for 
tracking other things (like nullable).

The current scheme of only narrowing, but never widening is 
overly pessimistic, most likely confusing and difficult to 
explain/justify to newcomers.







More information about the Digitalmars-d mailing list