very simple example code here. It returns that value if the argument is an even number, and returns the string "odd" if the argument is odd.
proc hoge(x: int): int|string =
if x mod 2 == 0:
return x
return "odd"
compile error
(4, 12) Error: type mismatch: got <string> but expected 'int'
What I really want to do is a bit more complicated. I want to define a method that returns different objects by conditional branching using case..of.
type
A = ref object of RootObj
name: string
value: string
B = ref object of RootObj
name: string
type C = ref object of RootObj
flg: string
proc parseStatement(self: C): A|B =
case self.flg
of "A":
return A(name: "a", value: "val")
of "B":
return B(name: "b")
else:
null
let c = C(flg: "a")
c.parseStatement()
If this is TypeScript, I can think of two solutions. The first one is to define the interface. The second one is to use Union types.
If you use the interface, it will be as follows.
// TypeScript
interface Hoge {
name: string;
}
class A implements Hoge {
public value: string;
constructor(public name: string, value: string) {
this.value = value;
}
}
class B implements Hoge {
constructor(public name: string) {}
}
class C {
constructor(public flg: string) {}
hoge(): Hoge { // here!!!
switch (this.flg) {
case 'A':
return new A('A', 'val');
case 'B':
return new B('B');
default:
return null;
}
}
}
It is easier to use Union types, even if you do not define an interface, you can write like this.
// TypeScript
class C {
constructor(public flg: string) {}
hoge(): A | B { // here!!!
switch (this.flg) {
case 'A':
return new A('A', 'val');
case 'B':
return new B('B');
default:
return null;
}
}
}
What I'd like to ask is how to solve this problem. In the case of Nim, I think that we will use concept rather than interface. Actually, any method can be used as long as it can be solved, but if you have enough capacity to show Nim better, please suggest multiple solutions.
I read the document about concept, but it was abstract and I could not understand well. I would be happy if you could write simple code as a concrete example.
Thanks you for your time.
import json
proc hoge(x: int): JsonNode =
if x mod 2 == 0:
return %x
return %"odd"
@mrsekut
First, your code has a problem by passing a small 'a' but parseStatement expects a capital 'A' or 'B'.
I'm a bit confused by your approach but I'll try to help anyway.
type
A = ref object of RootObj
name: string
value: string
B = ref object of RootObj
name: string
C = ref object of RootObj
flg: string
None = ref object of RootObj
proc parseStatement(self: C): ref RootObj =
case self.flg
of "A":
result = A(name: "a", value: "val")
of "B":
result = B(name: "b")
else:
result = cast[None](0)
# now, test it
let c = C(flg: "A")
let resc = c.parseStatement()
echo resc.repr
let d = C(flg: "?") # unknown/invalid
let resd = d.parseStatement()
echo resd.repr
let e = C(flg: "B") # unknown/invalid
let rese = e.parseStatement()
echo rese.repr
works and is probably what you wanted.
Side note re. small vs capital 'a' etc.: You might find it interesting to know that Nim's case accepts multiple options or ranges, too. So the follwing might be closer to what you had in mind:
proc parseStatement(self: C): ref RootObj =
case self.flg
of "A", "a":
result = A(name: "a", value: "val")
of "B","b":
result = B(name: "b")
else:
result = cast[None](0)
# now, test it
I did not know that ref RootObj can be specified as the return type of proc.
I'm sorry. The part you pointed out is a typographical error.
The problem was solved. Thank you for your politeness.
Thanks to your answer my problem has been solved.
By the way, can you solve this problem using concepts? Or do not you use concepts in such a situation?
By the way, Can I create a method in the Int structure of the above example code?
image. however, this results in a compile error.
proc addTwo(self: Int): int =
return self.num + 2
It works as follows, but if you use it incorrectly for a different structure, it will result in a runtime error.
proc addTwo(self: C): int =
return self.num + 2
echo b.addTwo() # ok
echo a.addTwo() # runtime error
Although it is possible to branch conditionally by typing like TypeScript type guard, it is annoying to write this each time.
proc addTwo(self: C): int =
if self.kind == Int:
return self.num + 2
else:
return 10000000
Please tell me if there is a better way.
oh, sorry. "the above code" is from alehander42's answer.
type
CKind* = enum Int, String
C* = object
case kind*: CKind:
of Int:
i*: int
of String:
text*: string
var b = C(kind: Int, i: 0)
var a = C(kind: String, text: "")
I'd like to know how to write methods for 'Int' and 'String' structures in this code.
Usually you do write a single function and use case or a pattern matching library instead of if.
This makes sense, as it's easy to guarantee that you handle all possible cases(at least when you use case) and it usually leads to less code(no signatures for each case).
If you really want to have a separate declaration for each, you can use something like https://github.com/alehander42/poly (disclaimer: a lib of mine), but it's not very typical nim style.
proc addTwo(self: C): int =
case self.kind
of int: result = self.num + 2
of string: result = 10_000_000
else: {.fatal: "Meh, illegal case in addProc" .}