The first Nimony progress thread became too long to. This thread is the 2nd progress report for Nimony.
Recently this program compiled (and produced the correct output):
import std / [syncio]
type
BinaryTree[T] = ref object
le, ri: nil BinaryTree[T]
data: T
proc newNode*[T](data: sink T): BinaryTree[T] = BinaryTree[T](data: data)
proc append*[Ty: Comparable](root: var nil BinaryTree[Ty], n: BinaryTree[Ty]) =
# insert a node into the tree
if root == nil:
root = n
else:
var it = root
while it != nil:
var c = cmp(n.data, it.data)
if c < 0:
if it.le == nil:
it.le = n
return
it = it.le
else:
if it.ri == nil:
it.ri = n
return
it = it.ri
proc append*[Ty](root: var BinaryTree[Ty], data: sink Ty) =
append(root, newNode(data))
type
Stringable = concept
proc `$`(x: Self): string
proc toString[T: Stringable](n: nil BinaryTree[T]; result: var string) =
if n == nil: return
result.add $n.data
toString n.le, result
toString n.ri, result
proc `$`*[T](n: BinaryTree[T]): string =
result = ""
toString n, result
proc main =
var x = newNode("abc")
x.append "def"
echo $x
main()
Feel free to continue the discussion about what syntax to use for nil ref T, ref T not nil, unchecked ref T here.
var x: ref Obj of Nilable
var y: ref Obj of NonNil
Neat to see the progress :-)
Regarding the not nil syntax, I like "not nil ref T", but I don't like "nil ref T" as much. To me "nil ref T" reads as "this is nil", rather than "this may be nil". It's not a big issue, but if we are looking for an alternative, what about using "not nil" for refs that cannot be nil, but use something else scuh as "maybe" or "nillable" for those that can? That is:
var x: not nil ref RootObj # Non-nil
var y1: nillable ref RootObj # Nillable option 1
var y2: maybe ref RootObj # Nillable option 2
this has the benefit of making them quite different, making them easy to distinguish. Of course some might think that them being so different is a negative rather than a positive. It also has the negative of requiring the addition of a new keyword.le, ri: nil BinaryTree[T]
Does that mean nimony will default to not nil? In such case I'd love BinaryTree[T] or nil syntax to opt out. It's syntactically similar to existing BinrayTree[T] not nil, which I find pretty natural. I'd also appreciate some global flag to disable not-nil-by-default behavior for at least a year, so that we have time to migrate. Otherwise I'm very excited about this (cough breaking) change! :)
I think it would be nice to have a clearer visual distinction between the different kinds of references, since it's a lot of “fun” to read the full type descriptor to see what it really is (especially since they are currently in opposite sides of each other). As an example, you could use the good old ! and ? symbols after the ref keyword. This would be grammatically simple, as well as more visually clear.
For example:
type UncheckedRef[T] = ref T
type NillableRef[T] = ref? T # instead of `nil ref T`
type NotNilRef[T] = ref! T # instead of `ref T not nil`
But I understand that this may be unwanted, since elsewhere the language almost never uses any symbols for such things.
Does that mean nimony will default to not nil?
Yes but the plan is to have a switch like {.refs: unchecked|notnil.} for a migration period.
In such case I'd love BinaryTree[T] or nil syntax to opt out. It's syntactically similar to existing BinrayTree[T] not nil, which I find pretty natural.
I find or nil too similar to not nil. When skimming code this is quite unclear IMO.
I like the or nil version, maybe this looks a bit more distinct:
type NillableRef[T] = ref T or nil
type NotNilRef[T] = ref T is val
And a couple more variants:
type NillableRef[T] = nilref T # short for Nillable Reference
type NotNilRef[T] = valref T # short for Value Reference (always points to value)
type NillableRef[T] = opt ref T
type NotNilRef[T] = val ref T
I like the simplicity of nil not nil prefix. @Saffage version looks very readable too :
type UncheckedRef[T] = ref T
type NillableRef[T] = ref? T # instead of `nil ref T`
type NotNilRef[T] = ref! T # instead of `ref T not nil`
I highly prefer multiple pages, and even besides preference, it makes it much easier to share links to specific documentation.
Also, Google and other search engines don't give you links to # sections of webpages as far as I can tell, they just give you links to the whole thing, making searching for docs harder.
When did Nimony strings diverge from Nim 2 strings and stop being null-terminated?
Ever since Nimony gained a string implementation. That said, I agree that it's annoying... We should probably stop chasing the slices (which you can get with openarrays already anyway) and instead go for SSO strings that keep the zero terminator.
"No forward declarations for procs and types required."
Could / should it be done for const too, to declare them out of order? For example to move a large block of them to the end of a file.
Ever since Nimony gained a string implementation. That said, I agree that it's annoying... We should probably stop chasing the slices (which you can get with openarrays already anyway) and instead go for SSO strings that keep the zero terminator.
Will this require rewriting the strutils, parseutils and friends with concepts? I've once rewritten strutils to use openArray[char] and it didn't require much changes to the code if any. But it broke too many things in (regards to resolution) to proceed.
Not being able to, say, use startsWith on openArray is pretty annoying.
Will this require rewriting the strutils, parseutils and friends with concepts?
openArray[char] is one of the few abstractions that the hardware instruction set directly supports and so we don't need generics here. (And concepts are just generic constraints.)