How to write my own prelude (def == without calling itself)

I intend to write a toy OS kernel in Crystal. Now I need to replace the prelude with a simple one of my own making. The first thing I tried to implement is the comparison operator. It is awesome how Crystal allows you to replace/extend such core constructs.

I know that writing a kernel is a complicated thing and there will be problems with stuff like the GC but others have solved that before.

Now my problem, when I write it as:

struct UInt64 
    def ==( other : UInt64 )
       self == other
    end
end

The function of course calls itself in an infinite loop. I tried to skim through the crystal source code and that of other mini OS kernels on GitHub but couldn’t find the solution.

Lilith declares this as @[Primitive(:binary)] but I get this error msg when trying that: Error: BUG: unhandled primitive in MainVisitor: binary

Many thanks in advance!

I think you can convert to another type for comparison, compare the memory, perform an XOR operation, or inherit the method from the parent class to avoid infinite recursion.

struct UInt64
  def ==(other : UInt64)
    self.unsafe_as(StaticArray(UInt8, 8)) == other.unsafe_as(StaticArray(UInt8, 8))
  end
end
struct UInt64
  def ==(other : UInt64)
    x = self
    pointerof(x).memcmp(pointerof(other), 1).zero?
  end
end
struct UInt64
  def ==(other : UInt64)
    (self ^ other).zero?
  end
end
struct UInt64
  def ==(other : UInt64)
    super
  end
end
2 Likes

You forgot to declare Bool as the return type, that’s why MainVisitor complains

2 Likes

You can take the code in primitives.cr for reference:

Unfortunately, it’s a bit more complicated than necessary due to macro deduplication. It should be fairly easy to understand.
And as HertzDevil mentioned, the primitive binding requires a full method signature, including the return type restriction.

2 Likes

This is trickier than it looks. All the snippets @Sunrise posted rely on some other prelude functions which at some point need to be implemented without the help of other yet to defined functions. But yeah the solution @HertzDevil posted works once I added the return type.

For a custom prelude, you must either require or reimplement most of:

require "lib_c"
require "primitives"
require "c/stddef"
require "intrinsics"

You’ll also have to implement or stub the __crystal_* funs expected by codegen, as well as the raise def and some exception types (TypeCastError, IndexError).

You might be interested by nano that takes care of all of that.

1 Like