I noticed that you can't put a concept in a generic.
PluggableHashAlgorithmU64 = concept x
x.open_default(self: var PluggableHashAlgorithmU64)
# if you do this:
# x.hash(self: PluggableHashAlgorithmU64; input: pointer; length: int): uint64
# it will fail to build even though thats valid function syntax
# XXX will have to bother upstream about this goofup
x.hash(self: var PluggableHashAlgorithmU64, input: pointer, length: int) is uint64
x.close(self: var PluggableHashAlgorithmU64)
FakeHashMap[K,V:typedesc,H:PluggableHashAlgorithmU64] = object
hash*: H
dummy_key: K
dummy_value: V
In version 2.0.0 you will get an error like this:
Error: cannot instantiate FakeHashMap [type declared in /home/icedquinn/code/science-fusedhash/fused.nim(12, 4)]
got: <typedesc[string], typedesc[int], typedesc[FakeBlake3]>
but expected: <K, V, H: PluggableHashAlgorithmU64>
This is a little disappointing though I suppose not critical. Nim will thankfully let us call whatever on H and try to get away with it (especially with defensive when compiles to make those call hooks optional) but I thought I'd try out concepts.
(before anyone asks, what i was trying to do is fix the icedmaps module so it no longer relies on closures and lets you bake in the hash algorithm at compile time)
I have no idea what you were trying to do with the concept. You seem to be mixing newstyle with old style and have created a monstrosity of wrong :D
type
PluggableHashAlgorithmU64 = concept x, var varx
open_default(varx)
# if you do this:
# x.hash(self: PluggableHashAlgorithmU64; input: pointer; length: int): uint64
# it will fail to build even though thats valid function syntax
# XXX will have to bother upstream about this goofup
hash(varx, pointer, int) is uint64
close(varx)
FakeHashMap[K,V:typedesc,H:PluggableHashAlgorithmU64] = object
hash*: H
dummy_key: K
dummy_value: V
type MyType = object
proc openDefault(_: var MyType) = discard
proc close(_: var MyType) = discard
proc hash(_: var MyType, _: pointer, _: int): uint64 = discard
var a = FakeHashMap[int, string, MyType]()
"monstrosity of wrong"
I want a sticker for my laptop with this
I have no idea what you were trying to do with the concept. You seem to be mixing newstyle with old style and have created a monstrosity of wrong :D
I guess it got confused by the x.thing, intuited the self parameter, then concluded the type signatures didn't match. Which is correct. Although the compiler just said the type "didn't match" and said I gave it a typedesc instead of being a tad more obvious that yes that is the kind of thing that should go here but it doesn't match the contract.
I wanted to use a concept because I was hoping the error would be something like, "you gave me FakeUnpublishedHashAlgo but its missing these signatures" so downstream users would get an obvious failure report.
Nup.
type
PluggableHashAlgorithmU64 = concept var x
open_default(x)
# if you do this:
# x.hash(self: PluggableHashAlgorithmU64; input: pointer; length: int): uint64
# it will fail to build even though thats valid function syntax
# XXX will have to bother upstream about this goofup
hash(x, pointer, int) is uint64
close(x)
FakeHashMap[K,V:typedesc,H:PluggableHashAlgorithmU64] = object
hash*: H
dummy_key: K
dummy_value: V
proc open[K,V,H](self: var FakeHashMap[K,V,H]) =
self.hash.open_default()
proc `[]`[K,V,H](self: FakeHashMap[K,V,H]; key: K): V =
return self.dummy_value
proc `[]=`[K,V,H](self: var FakeHashMap[K,V,H]; key: K; value: V) =
self.dummy_key = key
self.dummy_value = value
proc close(self: var FakeHashMap) =
self.hash.close()
type
FakeBlake3 = object
proc open_default(self: var FakeBlake3) {.inline.} =
echo "started blake3 with default settings"
proc close(self: var FakeBlake3) {.inline.} =
echo "shut down blake"
proc hash(self: var FakeBlake3; stuff: pointer; len: string): uint64 =
return 4; # determined by fair die roll
var k = FakeHashMap[string, int, FakeBlake3]()
k.open() # initialize in place
k["foo"] = 200
var foo = k["foo"]
k.close() # clean up in place
Version 2.0.0 still gives the same error
cannot instantiate FakeHashMap [type declared in /home/icedquinn/code/science-fusedhash/fused.nim(12, 4)]
got: <typedesc[string], typedesc[int], typedesc[FakeBlake3]>
but expected: <K, V, H: PluggableHashAlgorithmU64>
Does this require an unstable build to work?
Also you shouldn't libit K and V to be typedesc
True, but the error message says got: <typedesc[string], typedesc[int], typedesc[FakeBlake3]>.
FakeHashMap[K,V;H:PluggableHashAlgorithmU64] = object
the semicolon here seems pretty inconsistent with what people have been telling me is the current style. i used semicolons to separate arguments in function parameters because this is what we used to do and what c2nim does, and people told me we're supposed to use commas always now as in a, b: c, d: e. i ignore that advice because "a, b: c; d: e" is very explicit. apparently, that applies here too.
Concept error messages should really be improved..
Yup :woozy:
This version ultimately ended up working:
type
PluggableHashAlgorithmU64 = concept var x
open_default(x)
# if you do this:
# x.hash(self: PluggableHashAlgorithmU64; input: pointer; length: int): uint64
# it will fail to build even though thats valid function syntax
# XXX will have to bother upstream about this goofup
hash(x, pointer, int) is uint64
close(x)
# the semicolon is important here to separate the types
FakeHashMap[K,V; H:PluggableHashAlgorithmU64] = object
hash*: H
dummy_key: K
dummy_value: V
proc open[K,V,H](self: var FakeHashMap[K,V,H]) =
self.hash.open_default()
proc `[]`[K,V,H](self: FakeHashMap[K,V,H]; key: K): V =
return self.dummy_value
proc `[]=`[K,V,H](self: var FakeHashMap[K,V,H]; key: K; value: V) =
self.dummy_key = key
self.dummy_value = value
proc close(self: var FakeHashMap) =
self.hash.close()
type
FakeBlake3 = object
proc open_default(self: var FakeBlake3) {.inline.} =
echo "started blake3 with default settings"
proc close(self: var FakeBlake3) {.inline.} =
echo "shut down blake"
proc hash(self: var FakeBlake3; stuff: pointer; len: int): uint64 =
return 4; # determined by fair die roll
var k = FakeHashMap[string, int, FakeBlake3]()
k.open() # initialize in place
k["foo"] = 200
var foo = k["foo"]
k.close() # clean up in place
This feels like a woozy way of aspect programming. The intended case is to make the hash function external to the map and allow you to pick it at compile time. Right now I rely on a closure being passed in which has been working fine but its goofy and there's no need for that to be replaceable at runtime.
But it ought to work, so I'll take a look.