Skip to content

Instantly share code, notes, and snippets.

@treytomes
Last active January 11, 2024 16:18
Show Gist options
  • Save treytomes/323b51aa10fee6870d0d4c8da7bdb7ab to your computer and use it in GitHub Desktop.
Save treytomes/323b51aa10fee6870d0d4c8da7bdb7ab to your computer and use it in GitHub Desktop.
////
// Weird experiment to see what Rust-style traits might look like in MiniScript.
////
import "listUtil"
import "stringUtil"
PartialEq = {}
PartialEq.eq = function(other)
return refEquals(self, other)
end function
////
Display = {}
Display.fmt = function(f="", _self=null)
if _self == null then _self=self
if f.len == 0 then return str(_self) else return f.fill(_self)
end function
////
Point = {}
Point.init = function(x, y)
self.x = x
self.y = y
return self
end function
Point.make = function(x, y)
return (new Point).init(x, y)
end function
////
// And now, to implement the PartialEq and Display traits on Point.
map.typeName = function()
value = self
if value.hasIndex("__isa") then value = value.__isa
// I'm using this loop in place of the index search, because the ordering of values and indexes is not determinant.
for kv in globals
if kv.key.startsWith("_") then continue
if refEquals(kv.value, value) then return kv.key
end for
return "unknown"
end function
map.implement = function(type)
for kv in type
// Don't copy system values.
if kv.key[0] != "_" then self[kv.key] = @kv.value
// self[kv.key] = @kv.value
end for
// `_implements`, not `__implements`, as the double-underscore is reserved for the system.
if not self.hasIndex("_implements") then
self._implements = []
end if
self._implements.push type
return self
end function
map.implements = function(type)
if self isa type then
return true
end if
if self.hasIndex("_implements") and self._implements.contains(type) then
return true
end if
// I'm keeping this duck-typing loop as a fallback. For now.
for k in type.indexes()
if not self.__isa.indexes.contains(k) then
return false
end if
end for
return true
end function
// Actually, if you do some smarty-smart things with the `globals`, reassigning the original type is no longer required.
Point.implement PartialEq
// Example of overriding default trait behavior.
PointDisplay = new Display
PointDisplay.fmt = function(f="")
if f.len == 0 then f = "-->({x}, {y})"
// return f.fill(self)
// We're not copying `__isa` in the `implements` function anymore, so `super` is now a Point reference.
// return super.fmt(f)
return Display.fmt(f, self)
end function
Point.implement PointDisplay
p = Point.make(10, 12)
// The problem here, is that `p isa Point` is true, but `p isa Display` is false.
print "Built-in type-check:"
print "Is Point? {0}".fill([ p isa Point ])
print "Is Display? {0}".fill([ p isa Display ])
print "Is PartialEq? {0}".fill([ p isa PartialEq ])
print "====="
// An alternative approach: does `p.__isa.indexes` contain everything from `Display.indexes`?
print "With `implements`:"
print "Is Point? {0}".fill([ p.implements(Point) ])
print "Is Display? {0}".fill([ p.implements(Display) ])
print "Is PartialEq? {0}".fill([ p.implements(PartialEq) ])
print "====="
print p.fmt("x={x}, y={y}")
print p.fmt // The overridden Display for Point will allow this to be rendered properly.
print p.fmt("({x}, {y})")
print "====="
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment