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

Generics proc + macros: identifier resolution happens before macros #6387

Closed
mratsim opened this issue Sep 16, 2017 · 8 comments
Closed

Generics proc + macros: identifier resolution happens before macros #6387

mratsim opened this issue Sep 16, 2017 · 8 comments

Comments

@mratsim
Copy link
Collaborator

mratsim commented Sep 16, 2017

From mratsim/Arraymancer#43

In generic procs, identifier resolution happens before macro replacement.

This prevent the uses of jokers for slicing inside procs for example: "foo[1, _, 2]" for a multidimensional array.

Test case:

issue_43.nim

import macros

type CustomSeq*[T] = object
  data*: seq[T]

macro `[]`*[T](s: CustomSeq[T], args: varargs[untyped]): untyped =
  ## The end goal is to replace the joker "_" by something else
  result = newIntLitNode(10)

when isMainModule:
  let a = CustomSeq[int](data: newSeq[int](10))
  echo a
  echo a[_]  # <---- works fine

issue_43_test.nim

import issue_43

#### Fails: undeclared identifier: '_'
proc foo[T](): CustomSeq[T] =

  let bar = CustomSeq[T](data: newSeq[T](20))
  echo bar[_]
  return bar

discard foo[int]()
####

# #### Works correctly
# let baz = CustomSeq[int](data: newSeq[int](20))
# echo baz[_]


# ## Works correctly
# proc foo(): CustomSeq[int] =
#   let bar = CustomSeq[int](data: newSeq[int](20))
#   echo bar[_]
#   return bar
# 
# discard foo()
@Araq
Copy link
Member

Araq commented Sep 18, 2017

I think you need to add mixin _ and read about mixin in the manual.

@mratsim
Copy link
Collaborator Author

mratsim commented Sep 19, 2017

Indeed it works with mixin

import issue_43

#### Fails
proc foo[T](): CustomSeq[T] =
  mixin _
  let bar = CustomSeq[T](data: newSeq[T](20))
  echo bar[_]
  return bar

discard foo[int]()

However this is not ideal for library writers, that means that everyone who uses proc on my types have to use mixin _.

@Araq
Copy link
Member

Araq commented Sep 20, 2017

So design the libraries that play well with Nim.

@Araq Araq closed this as completed Sep 20, 2017
@krux02
Copy link
Contributor

krux02 commented Sep 20, 2017

Well I am actially supporting the issue. I just think this is an unnecessary inconsistency that does not need to be there. I did some changes to the file to make it a little bit more obvious:

import macros

type CustomSeq*[T] = object
  data*: seq[T]

macro `[]`*[T](s: CustomSeq[T], args: varargs[untyped]): untyped =
  ## The end goal is to replace the joker "_" by something else
  result = newIntLitNode(10)

proc foo1(): CustomSeq[int] =
  result.data.newSeq(10)
  # works fine
  echo result[_]

echo foo1()

proc foo2[T](): CustomSeq[T] =
  result.data.newSeq(10)
  # works fine with generics
  echo result[_]

echo foo2[int]()
import issue_43

proc foo3(): CustomSeq[int] =
  result.data = newSeq[int](10)
  # works fine from other module
  echo result[_]

echo foo3()

proc foo4[T](): CustomSeq[T] =
  result.data.newSeq(10)
  # weird fancy corner case that feels special and wants special treatment
  mixin _
  # why?
  echo result[_]

echo foo4[int]()

@edubart
Copy link
Contributor

edubart commented Sep 20, 2017

I'm also supporting the issue, is there other workaround for this?

@Araq
Copy link
Member

Araq commented Sep 20, 2017

Well I am actially supporting the issue.

As if I don't know.

I just think this is an unnecessary inconsistency that does not need to be there.

Yes, that's what you think. But you're wrong.

I did some changes to the file to make it a little bit more obvious:

Again, I know. There are various tradeoffs involved here and the current scheme took weeks to refine. I'm tired of you know-it-alls. You seem to think in trigger words only, that an inconsistency can be the cause of a conscious design decision never ever occurs to you.

Here is a hint: The following should not compile:

proc foo[T](x: var Table[string, T]; val: T) =
  a["key"] = val # typo: 'x' meant here

# test foo
var a = initTable[string, int]()
foo(a, 4)

Now think about what that means...

@mratsim
Copy link
Collaborator Author

mratsim commented Sep 21, 2017

So my workaround would be to export a _*. It will have a very high value so that people do not have silent bugs.

It doesn't change tuple destructuring so that's good but I don't know if there are other use of this _ symbol

import macros
type CustomSeq*[T] = object
  data*: seq[T]

## <--- this is the change
const _* = high(int)

macro `[]`*[T](s: CustomSeq[T], args: varargs[untyped]): untyped =
  ## The end goal is to replace the joker "_" by something else
  result = newIntLitNode(10)

when isMainModule:
  let a = CustomSeq[int](data: newSeq[int](10))
  echo a
  echo a[_]  # <---- works fine

## Checking tuple desctruturing
let a = (1, 2, 3)
let (_, b, c) = a # works as expected
let _, d, e = a # Strange that it compiles

echo b
echo c

@ghost
Copy link

ghost commented Sep 21, 2017

@mratsim

let _, d, e = a

Would set _, d, e variables to value of "a"

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