-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
universal conversion operator (cf D's a.to!T
) (std.conv.to)
#84
Comments
The good thing about Nim is: you can implement such a universal conversion library yourself and make it available for others to try it out. Asking others to write something like that for you is probably a waste of time. |
I mainly submitted this bug report for these reasons:
If noone gave it a try I guess I could give it a try |
some interesting stuff from the Nim Manual: |
This is the analogous to your example, no need to support this especially in the language type A = object
proc to(a: A, x: typedesc[float32]): float32 = 1.0
proc to(a: A, x: typedesc[float64]): float64 = 1.0
let a = A()
echo a.to(float32) |
Sounds useful: import strutils, json
template to(source: string; dest: typedesc[bool]): untyped = parseBool(source)
template to(source: string; dest: typedesc[int]): untyped = parseInt(source)
template to(source: string; dest: typedesc[float]): untyped = parseFloat(source)
template to(source: string; dest: typedesc[JsonNode]): untyped = parseJson(source)
echo "yes".to(bool)
echo "0034".to(int) |
@Araq https://nim-lang.org/docs/marshal.html uses |
@timotheecour One reason is that Morever the signature of |
Additionally, |
Relating to the linked issue the |
I really like this idea by the way. Converting to string is easy enough in Nim with |
should this be in a nimble package or in the standard library?
|
Also if someone needs a little bit of sugar: import strutils, json
template genTo(srcTyp, destTyp: typedesc, body: untyped): untyped {.dirty.} =
template to(source: srcTyp; dest: typedesc[destTyp]): untyped =
body
genTo(string, bool): parseBool(source)
genTo(string, int): parseInt(source)
genTo(string, float): parseFloat(source)
genTo(string, JsonNode): parseJson(source)
genTo(int, float): float(source)
echo "yes".to(bool)
echo "0034".to(int)
echo 5.to(float) |
genTo(string, XmlNode): parseXml(source)
genTo(string, DateTime): parse(source, "yyyy-MM-dd HH:mm:sszzz") But for DateTime not very good. |
@data-man why it's not good for DateTime ? :) |
@Yardanico |
@data-man that's a problem with a format string you've used to parse though, change it (remove zzz and it will work without timezone) |
@Yardanico if scanf(source, "$i-$i-$i", y, m, d):
...
elif scanf(source, "$i-$i-$i$s$i:$i:$i", y, m, d, hh, mm, ss):
...
elif scanf(source, "$i-$i-$i$s$i:$i:$i.$i$s$w", y, m, d, hh, mm, ss, ms, tz):
... |
Please look at my 1st attempt: nim-lang/Nim#7488 and design principles I outlined there |
to[T] can also be overloaded, eg with I've created an issue https://github.com/nim-lang/Nim/issues/7517 ([RFC] guidelines for when to use typedesc vs generics) to discuss this particular aspect more generally as it seems to keep popping up in different contexts |
Well, yes, there is an overlap, but I would never use |
@andreaferretti, why not? That's just how partial specification works in C++. |
It's only weird if you're used to Java or other languages with limited metaprogramming support |
Actually, the languages I am used most are Scala and Nim and the latter has nice support for this case in the form of typedesc parameters :-) |
I mean, I know it can be used this way, it just looks ugly compared to just passing the type as a parameter |
Can we start with description of what is supposed to be implemented under this generic name? If it's supposed to only parse strings, then "123".parse(bool) indeed looks more clear. If it's supposed to handle other input types, the question is why we need to have a generic name for it? And may be longer name such as If we don't yet have justification for generic conversion function, I propose to put this idea on hold. And anyway, using As @Araq mentioned, with |
On the second thought, I think I found the culprit: It's debatable whether string representation is the same data as container or so, especially since we can (de)serialize using XML, or pretty-printing, or with raw binary data. So I think that we should separate those two questions - strings should be processed with |
My vote is for |
I like the originally proposed Update: I'd like to not allocate a special "parse" just for "from string" case. I don't think that is too special of a case. String is just another type. A "to" works for all type representation conversions. |
Actually it is not ambiguous. You |
OK, may be I got confused.. I thought this issue was to convert any type to any other type as I show in that table linked on my scripter.co page referenced in the first comment of this thread. If |
Are we talking about the same thing? That's why I like the original |
@kaushalmodi look at https://github.com/nim-lang/Nim/issues/7430#issuecomment-406054435 :
|
@Bulat-Ziganshin Thanks, I missed that comment. That explains my confusion. I'm not so sure about distinction between "parse" and "convert". I don't see "from string" as a special case.. it's just another type. |
@kaushalmodi make sure that you have read https://github.com/nim-lang/Nim/issues/7430#issuecomment-406049952 and entire https://github.com/nim-lang/Nim/issues/7430#issuecomment-406054435 Let's elaborate: you can convert one type to another type by a number of ways. For example, you can convert from string by parsing it as XML, JSON, Nim constant, asm constant and so on. So my point is that While This makes parsing and converting different operations. While each parse and convertTo specialization is implemented in ad-hoc manner, usually by the package providing corresponding types, the language spec should provide these strict recommendations about functionality of the operations, and reject any contributions to standard libraries violating them. |
Luckily the OP didn't get a chance to hear this from this forum -- "Looking in internet to find a help in coding is waste. Try to create your own programming language from scratch." |
Creating a Nimble package is not the same as "create your own programming language". |
Reiterating my comment on a PR: In line with import strutils
proc to(x: var float, str: string) = x = parseFloat(str)
var f: float
to(f, "1.0") This is nice because we can have a generic template `as`[T](toConvert: untyped, _: typedesc[T]): T =
var converted: T
to(converted, toConvert)
converted
# with previous code block:
doAssert ("1.0" as float) == 1.0 We can also do things like get information from the type Obj = object
changeSign: bool
num: int
proc to(obj: var Obj, n: int) =
if obj.changeSign:
obj.num = -n
else:
obj.num = n
var obj = Obj(changeSign: true)
to(obj, 5)
echo obj.num # -5 Sidenote: I don't think a name like |
Here's my proposal:
template to*[S](a: S, T: typedesc): T =
var ret: T
mixin from
from(ret, a)
ret
proc from[T, S](result: var T, a: S) =
... code looks/reads naturally whether you use inplace (to) or outplace (from), eg: # outplace form
echo s.bar.to(JsonNode)
echo s.bar.to BsonNode # obviously, also works without ()
# inplace form; eg when you want to reuse object to avoid allocations
var ret: Foo
foo.from(JsonNode)
This is one of the main design goals of nim-lang/Nim#12076, which allows you to retrieve the symbol (if any) that would be selected after sigmatch (or nil if no match): foo.from(bar) # which `from` was picked? where is it declared?
inspect foo.from(bar) # this gives you the symbol selected after sigmatch (or prints where it's declared) note that special case: converting to string and parsing from stringthese are so common they deserve a special case (but
note
|
As github syntax highlighting shows first thing in your post
If all else fails, this should be in a package, so people can choose whether they want an operator or a keyword. Other packages can provide support with a simple export. Update: The best name I can come up with for the proc is "absorb", or something along those lines. What's most preferred is a name that also works for #191, which I was taking into consideration before.
I trust you but I can't think of these, if your ideas of |
when true:# D20200506T234004
import strutils
proc `from`[T, S](result: var T, a: S) =
when S is string:
when T is int: result = parseInt a
elif T is float: result = parseFloat a
else: doAssert false
else: doAssert false
template to*[S](a: S, T: typedesc): untyped =
var ret: T
# mixin `from`
ret.from a
ret
template `as`*[S](a: S, T: typedesc): untyped =
var ret: T
ret.from a
ret
proc main()=
var ret: int
ret.from "12" # that's the from syntax that will be most often used
`from`(ret, "12") # works too, useful in templates to "bind early"
# ret from "12" # works pending https://github.com/nim-lang/Nim/pull/14241
doAssert ret == 12
doAssert "13".to(int) == 13
doAssert "13.2".to(float) == 13.2
let b = "13".to int
doAssert b == 13
doAssert "13.3".as(float) == 13.3
## only difference between to and as:
doAssert "13.3" as float == 13.3 # possible
# doAssert "13.4" to float == 13.4 # not possible
main()
well you have to "know" the precedence table and that it's not interpreted as
one of them was #163 but I'm now thinking this could be done with a pragma instead; other uses I had in mind could also be done with a pragma. What I'd really like is for
then let's make sure it doesn't fail :). #191 aside, one last thing: to reset or not to resetthat wasn't really discussed yet; IMO the thing that's overloaded should not reset: # everything is defined in terms of `addFrom`
proc addFrom*[T, S](result: var T, a: S) = .. # this is what gets overloaded
# no resetting of result
template `from`*[T, S](result: var T, a: S) = # single `from` template, doesn't get overloaded
result.reset # resets
result.addFrom(a)
template `as`*[S](a: S, T: typedesc): untyped = # single `to` template, doesn't get overloaded
var ret: T
ret.addFrom a
ret
Long story short
This gives a simple design where there's only 1 proc to overload, and you get |
This RFC is stale because it has been open for 1095 days with no activity. Contribute a fix or comment on the issue, or it will be closed in 7 days. |
in D
std.conv.to
allows universal type conversions, it's used very frequently and simplifies code a lot.Is there anything similar in nim? if not could we add it?
Instead in nim I see
parseInt
,parseBool
, etc which is:to
.proposed design:
see nim-lang/Nim#7488
related
The text was updated successfully, but these errors were encountered: