import typeinfo
type
A = distinct int
B = distinct int
var a = 0.A
let a_any = a.toAny
var b = 0.B
let b_any = a.toAny
proc bar(u:Any) : void =
if u of A: # Error: 'of' expects object types
"it's A"
elif u of B:
"it's B"
else:
"it's something else"
proc foo(u:Any) : void =
if u.rawType == a_any.rawType: # Error: undeclared field: 'rawType'
"it's A"
elif u.rawType == b_any.rawType:
"it's B"
else:
"it's something else"
foo(a.toAny)
foo(b.toAny)
bar(a.toAny)
bar(b.toAny)
this is a working version of what I would like to do, but it go:
package main
import "fmt"
type A int
type B int
func foo(t interface{}) {
switch t.(type) {
default:
fmt.Printf("something else\n")
case A:
fmt.Printf("it's A\n")
case B:
fmt.Printf("it's B\n")
}
}
func main() {
var a A
var b B
foo(a)
foo(b)
}
What about generics with [T] and compile-time conditional with when?
type
A = distinct int
B = distinct int
var
a = 0.A
b = 0.B
proc bar[T](u: T) =
when u is A:
echo "it's A"
elif u is B:
echo "it's B"
else:
echo "it's something else"
bar(a)
bar(b)
The Nim solution would be to have a wrapper through which varargs arguments get embedded in a polymorphic type.
This can be done with variant objects:
import strutils
type
WrapperEnum = enum
wrappedInt, wrappedFloat, wrappedString
WrappedItem =
object
case kind: WrapperEnum
of wrappedInt: intValue: int
of wrappedFloat: floatValue: float
of wrappedString: stringValue: string
proc wrap(x: int): WrappedItem =
WrappedItem(kind: wrappedInt, intValue: x)
proc wrap(x: float): WrappedItem =
WrappedItem(kind: wrappedFloat, floatValue: x)
proc wrap(x: string): WrappedItem =
WrappedItem(kind: wrappedString, stringValue: x)
proc sloppysum(a: varargs[WrappedItem, wrap]): float =
result = 0.0
for item in a:
case item.kind
of wrappedInt:
result += float(item.intValue)
of wrappedFloat:
result += item.floatValue
of wrappedString:
result += parseFloat(item.stringValue)
echo sloppysum(1, 2.0, "3.0")
or with inheritance:
import strutils
type
WrappedItem =
ref object of RootRef
Wrapped[T] =
ref object of WrappedItem
value: T
proc wrap[T](x: T): WrappedItem =
Wrapped[T](value: x)
proc sloppysum(a: varargs[WrappedItem, wrap]): float =
result = 0.0
for item in a:
if item of Wrapped[int]:
result += float(Wrapped[int](item).value)
elif item of Wrapped[float]:
result += Wrapped[float](item).value
elif item of Wrapped[string]:
result += parseFloat(Wrapped[string](item).value)
else:
raise newException(ValueError, "cannot evaluate items of this type")
echo sloppysum(1, 2.0, "3.0")
Edit: simplified some of the code.
@Jehan
I like your first solution. It reminds me very much of tagged unions. I have the impression with the help of macros I can make that pattern as easy to use as the rust enum. Your second solution depends on garbage collection. For my use case, I prefer a solution without that dependency.
@Araq Because with simple overloading the type needs to be known at compile time. That's not hte case for me.
@Krux02 In fact, there is a macro to generate tagged unions (albeit without the wrap functions, but with other conveniences).
It is called variant, and you can find it in my patty library. The other half of the library is another macro called match that performs a (still very limited and rough) form of pattern matching for such tagged unions.