nim-works/nimskull

Remove `bind` and `mixin` from generics

Open

#561 opened on Mar 1, 2023

 (2 comments) (0 reactions) (0 assignees)Nim (39 forks)auto 404
compiler/semhelp wantedsimplification

Repository metrics

Stars
 (346 stars)
PR merge metrics
 (PR metrics pending)

Description

Core Issue

bind and mixin are template metaprogramming features, which generics are not. Generics, or parametric polymorphism, have to do with types.

To put a very fine point on things:

proc foo[T](a, b :T): T

Is a procedure type, with a type parameter, meaning the type changes (polymorphic) based on said type parameter. It can be read as, foo is a procedure type, where for all T (universal), T, T -> T.

It's not arbitrary syntactic "fill in the blanks", those are templates and those are entirely different. Doing this will drive a major step in substantially improving our type system and digging deep into the fun bits.

Solution/Approach

Steps:

  1. in a branch remove bind and mixin from generics
  2. chase down compiler and stdlib issues until things work again (or close)
  3. use the lessons learned in the above steps to determine the alternative approach
  4. implement the alternative approach, this and any intermediate improvements are what will get merged

Steps 1 - 3 are there to discover the rest of the detailed solution, because mixin is a poor facsimile for late static type safe binding, which is fundamentally very useful. So some sort of alternative approach is required for generics to fill the gap the removal of mixin, especially, will leave behind.

If you'd like to work this issue please ping, @saem.

Early Thinking about Solution

This is mostly illustrative and not any sort of final design. The assumption is that early binding remains as the default behaviour and so the focus is on some mixin-ish feature/behaviour. Taking the mixin example form the manual (reproduced below):

proc create*[T](): ref T =
  mixin init   # <-- this will go away
  new result
  init result

With whatever mixin-ish thing we end up with, it should be equivalent to the following -- ignore the syntax, it's merely approximating the approximate goal using existing constructs:

proc create*[T, init: proc (T) | proc (T): ref T = init](): ref T =
  new result
  init result

Contributor guide