Skip to content
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

Converted parameters with to[T, toT] types #549

Open
xjzh123 opened this issue Jan 21, 2024 · 5 comments
Open

Converted parameters with to[T, toT] types #549

xjzh123 opened this issue Jan 21, 2024 · 5 comments

Comments

@xjzh123
Copy link

xjzh123 commented Jan 21, 2024

Abstract

A proc can declare that some certain parameter of it can take arguments of different types and convert them to certain types.

Motivation

Sometimes converters are used to simplify calling some routines, like here. But now that converters are global, they sometimes cause troubles, like here, leading to ambigious calls.
Now that converters are frequently used only for some specific routines, why not make routines, instead of types, have converters? We can already do similar things with generic, auto type, when and overloading, but this RFC can make it simpler to write such a conversion.

Description

Parameters can have "converters" (not Nim converters). This is like varargs, which can already convert arguments to certain types.
Like varargs, we can make this a special type, to:

proc foo(x: to[int]): int =
  2 * x

# This is the same
proc foo(x: auto): int =
  let x = int(x)
  2 * x

# This is also the same
proc foo[T](x: T): int =
  let x = int(x)
  2 * x

It is also useful to convert with certain routines:

proc toAddr[I; T](a: array[I, T]): ptr T = addr(a[0])

proc useAddr[T](p: to[ptr T, toAddr]) =
  discard # here p is ptr T

Like varargs, overloaded procs are used on demand:

# StringBuilder is an imaginary object type
proc add(x: StringBuilder, s: to[string, `$`]) =
  x.data &= s # if s is T, s is converted to string with (proc (T): string)`$`

If this proposal has downsides, I think:

  1. The semantic is not that readable. But with varargs already existing, it is still easy to understand.
  2. It still requires editing every proc
  3. It is easily replaced by existing syntax.

Code Examples

No response

Backwards Compatibility

No response

@ZoomRmc
Copy link

ZoomRmc commented Jan 21, 2024

This is already achievable with concepts:

type ToInt = concept x
  int(x) is int

proc foo(x: ToInt): int = 2 * x

doAssert foo(2.Natural) == 4

###
type
  ToString = concept x
    string(x) is string
  Stringlet = distinct string

proc add(x: var string; s: ToString) =
  x &= string(s)

var s: string = "what follows was "
s.add("not a string".Stringlet)

doAssert s == "what follows was not a string"

@xjzh123
Copy link
Author

xjzh123 commented Jan 24, 2024

This is already achievable with concepts:

type ToInt = concept x
  int(x) is int

proc foo(x: ToInt): int = 2 * x

doAssert foo(2.Natural) == 4

###
type
  ToString = concept x
    string(x) is string
  Stringlet = distinct string

proc add(x: var string; s: ToString) =
  x &= string(s)

var s: string = "what follows was "
s.add("not a string".Stringlet)

doAssert s == "what follows was not a string"

Ahh! idk that. fancy

@xjzh123
Copy link
Author

xjzh123 commented May 11, 2024

This is already achievable with concepts:

type ToInt = concept x
  int(x) is int

proc foo(x: ToInt): int = 2 * x

doAssert foo(2.Natural) == 4

###
type
  ToString = concept x
    string(x) is string
  Stringlet = distinct string

proc add(x: var string; s: ToString) =
  x &= string(s)

var s: string = "what follows was "
s.add("not a string".Stringlet)

doAssert s == "what follows was not a string"

Wait, I just discovered that you are doing explicit converting with string(s). You don't need to do it with Natural just because Natural already supports being multiplied with ints. Well... I know you can do explicit converting, but to[T, toT] will let you write less code...

@hugosenari
Copy link

Related #168

@arnetheduck
Copy link

. You don't need to do it with Natural just because Natural already supports being multiplied with ints.

this is also why we recommend to never use Natural as input parameters (or indeed, any range type) in production code since it performs an implicit narrowing conversion - an expression like let x = -1; let y = Natural(x) will panic at runtime, as would the code in this proposal if the conversions happen to be narrowing.

Indeed, what this RFC lacks a way to deal with narrowing conversions safely - these are more common than one would thing, ie string-to-int can obviously fail, as can many other common ones - in other words, for this to fly, it would ideally be constrained to non-narrowing conversions (ie conversions that don't panic or raise exceptions)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants