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

make genericParams support static[T] generic params #13433

Merged
merged 2 commits into from
Mar 2, 2020

Conversation

timotheecour
Copy link
Member

@timotheecour timotheecour commented Feb 19, 2020

before PR: genericParams didn't work with a generic containing static params (eg static int)
after PR: this works.

example

  type Bar[N: static int, T] = object
  type Bar3 = Bar[3, float]
  doAssert genericParams(Bar3) is (WrapStatic[3], float)
  doAssert genericParams(Bar3).get(0) is WrapStatic
  doAssert genericParams(Bar3).get(0).Val == 3
  doAssert genericParams(Bar[3, float]).get(0).Val == 3

This was referenced Feb 19, 2020
@timotheecour timotheecour requested a review from Araq February 19, 2020 08:15
runnableExamples:
type Foo[T1, T2]=object
doAssert genericParams(Foo[float, string]) is (float, string)
type WrapStatic*[Val] = object
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not export this.

Copy link
Member Author

@timotheecour timotheecour Feb 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's needed for generic code though, so user can tell whether generic param returned by genericParams is a static or a regular type (in fact the runnableExamples + ttypetraits tests would fail without exporting it)
the only other possibility I can think of is providing a new proc proc isWrapStatic*(T: typedesc): bool to test for that but that's just more complex

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm can't it produce static 1.0 instead of WrapStatic[1.0]?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can't work:

type Foo = (int, static[2])
Error: type expected, but got: 2
  type Foo = (int, static[2])

that's why WrapStatic is needed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping @zah

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why WrapStatic[T] works. I guess somebody relaxed the rules for matching generic parameters in another PR. I've never intended for the following to work, but Nim-devel seems to be happy about it:

type
  Foo[T] = object

var x: Foo["test"]

For me, this signature of Foo should allow only type parameters. Even worse version of the code is the following:

type
  Foo[T] = object
    x: T

var x: Foo["test"]
echo x

It currently compiles and prints:

(x: "")

Copy link
Member Author

@timotheecour timotheecour Feb 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(see #13529)
but there's no typeclass for static (representing tyStatic) at the moment, eg:
type WrapStatic[T:static] = object doesn't work (while type WrapStatic[T: static[float]] does, but that's not useful here)
so we should support type WrapStatic[T: static] = object, regardless of whether [T] should be allowed to match to a static (that's a debate to have elsewhere).
I think the way I wrote it is fine for today's nim, and once we add support for [T: static], we'll simply update this code to use type WrapStatic[T:static] = object instead
this can happen transparently without breaking any code that uses genericParams

Copy link
Member

@zah zah Feb 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I'm not fundamentally opposed to WrapStatic. It's helpful that it has less degrees of freedom when compared to tyStatic. I would call it StaticParam and then name the payload param value as it is possible to access it with the dot operator.

But all of this won't be necessary if we give up on the notion that genericParams should return a tuple type. We could have had another trait genericParam(N): typedesc that doesn't have these issues.

Copy link
Member Author

@timotheecour timotheecour Feb 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call it StaticParam and then name the payload param value as it is possible to access it with the dot operator.

done

But all of this won't be necessary if we give up on the notion that genericParams should return a tuple. We could have had another trait genericParam(N): typedesc that doesn't have these issues.

Note that this was my previous approach (#8554) but returning a tuple (which was your suggestion) is a better API, in particular it avoids needing 2 separate APIs (genericParam(N) + genericParamLen).
That being said, I don't understand this argument, you'd have the exact same problem with genericParam(N) if the Nth generic param is static:

type Bar[N: static int, T] = object
type Bar3 = Bar[3, float]

type t = genericParams(Bar3, 1)
doAssert t is float
type t2 = genericParams(Bar3, 0) # won't work unless you also use StaticParam
(or you'd need yet another API to check whether the N'th param is static, eg

when genericParamsIsStatic(N):
  const value = genericParamsValue(N)
else:
  type t = genericParams(N)

what I have in this PR is arguably much simpler to use, see usage in tests in ttypetraits.nim, eg:

doAssert genericParams(Bar3) is (StaticParam[3], float)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I've gone through the same motions in my own thinking.

Perhaps one day typedescs-as-values will have their revenge and we'll be able to make an alternative to genericParams that returns a real tuple value, not a type:

doAssert generamParams(Bar3) == (3, float)

Anyway, merging this is fine to me, but it would be nice if the funny business in #13529 is not postponed for later.

@timotheecour timotheecour force-pushed the pr_genericParams_value branch from 0bb4f10 to 6f61c6a Compare February 19, 2020 10:15
@timotheecour
Copy link
Member Author

@Araq is anything else needed in this PR?

@timotheecour timotheecour force-pushed the pr_genericParams_value branch from c3f267c to 5d62255 Compare March 2, 2020 09:49
@timotheecour timotheecour reopened this Mar 2, 2020
@Araq Araq merged commit 451b724 into nim-lang:devel Mar 2, 2020
@timotheecour timotheecour deleted the pr_genericParams_value branch March 2, 2020 22:16
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

Successfully merging this pull request may close these issues.

3 participants