Nim: nonpure enum can hijack pure enum; instead should give `Error: ambiguous identifier` ; pure and nonpure should both mean the same thing; pure should be deprecated

Created on 3 Sep 2018  路  9Comments  路  Source: nim-lang/Nim

ccing ppl from related discussion
/cc @Araq @dom96 @PMunch @mratsim

silent hijacking is bad.

now that https://github.com/nim-lang/Nim/commit/2f7b979e384ff6cc750e123939401a72c3f59093 was committed, I think we should do the following (see rationale below)

  • P1: nonpure enum clashing with pure enum should give Error: ambiguous identifier instead of hijacking it; see example below
  • P2: pure and nonpure should both mean the same thing (requires P2a, see below)
  • P3: pure should be deprecated (would become a noop under this proposal)

see https://github.com/nim-lang/Nim/issues/8066 for related discussion

when defined(case5):
  import typetraits
  type
    X {.pure.} = enum
      blue
      red
      magenta

    Y = enum
      blue
      orange
      red

  echo int(red) # prints 2 (not 1, nonpure takes over currently) but should give ambiguity error as in https://github.com/nim-lang/Nim/commit/2f7b979e384ff6cc750e123939401a72c3f59093

rationale:

imagine following scenario:

# thirdpartylib1.nim:
type
    X* {.pure.} = enum
      blue
      red
      magenta

# thirdpartylib2.nim:
# nothing yet

# myapp.nim:
import thirdpartylib1
import thirdpartylib2
call_c_library(int(red)) # call_c_library(1)

later thirdpartylib2.nim gets udpated as follows:

type
    Y* = enum
      blue
      orange
      red

Now call_c_library(int(red)) calls call_c_library(2)
this can lead to nasty bugs under the nose of application writer.
Instead the only sane way here is to give compile error: Error: ambiguous identifier (P1)

Which leads to P2 and P3 since now pure and impure would mean the same thing, modulo nit below (which shouldn't be relevant enough to warrant having 2 concepts)

P2a: things to resolve before merging pure and impure

  • [ ] impure allows UFCS: int.red , pure doesn't unless the symbol is qualified: X.red.int or int(red) ; if we are to do P2 and P3, I'm fine with either rule (allow or disallow UFCS without qualification (when unambigious))
  • [ ] impure disallows 2 enums with a member clash; pure allows it

I suggest following pure's rules in all cases

note

that seems in line with https://irclogs.nim-lang.org/22-10-2017.html#13:54:23

14:05:21 | Araq | well the point is to remove the whole distinction between the two enum types

links

Pure really removed for enums? - Nim forum

stale

Most helpful comment

I can confirm that's what will be done.

All 9 comments

echo int(red) # prints 2 (not 1, nonpure takes over currently) but should give ambiguity error

No, it works as expected and documented. It's true that I want to merge pure and non-pure enums though, eventually.

imagine following scenario...

These scenarios can always be conjectured and are not convincing. If they were, we wouldn't embrace overloading to begin with.

That isn't a very obscure scenario though.. I'd imagine a lot of people using enums this way, and any module that happens to use the same value for an enum would break that.. I'm still for bringing pure enums back, can't really see a reason to remove them..

Once we merged pure with non-pure enums completely the scenario is gone. And yes, call_c_library(int(red)) is a completely contrived example.

These scenarios can always be conjectured and are not convincing. If they were, we wouldn't embrace overloading to begin with.

with overloading you'd get compile error: ambiguous call: foo matches both foo(...) and foo(...) ; the case where it'd change meaning are more contrived: eg when thirdpartylib1 removes a foo overload and thirdpartylib2 adds a foo overload, for example.

And yes, call_c_library(int(red)) is a completely contrived example.

I don't think this is contrived, I just gave a simple example. This arises in many other scenarios, that silently give different results instead of compile error:

echo red
foo(red) # where `foo` is generic (and itself calls thing that accept either form of `red`)
$red
int(red)
type(red).name
type(red).sizeof
...

Once we merged pure with non-pure enums completely the scenario is gone.

great, then let's keep this issue open to track this :) ; so looks like we agree on P1,P2,P3

before merging pure and impure enum we need to resolve how they work in other aspects; see P2a: things to resolve before merging pure and impure (I just updated that paragraph)

@araq confirmed on gitter https://gitter.im/nim-lang/Nim?at=5bafb1e019b139275a1de6ac that
nonpure enum will be changed to behave as current pure enum (with pure's new meaning introduced since https://github.com/nim-lang/Nim/commit/2f7b979e384ff6cc750e123939401a72c3f59093), which allows both Foo.red and red wherever un-ambiguous), making {.pure.} both the new default and a no-op; this would therefore close this issue since "nonpure enum can hijack pure enum" won't happen after that.

(please correct me if I mis-understood)

I can confirm that's what will be done.

EDIT: i read somewhere (sorry, forgot whether it was in IRC or forum or github) that pure is now a no-op (ie implicit), however that's still not the case in latest devel (b2a5195e92f8852a47ca70136b103bc374b73393); pure and non pure still have different semantics

eg1:

type Goo = enum
  goo0,
  goo1,

type Foo {.pure.} = enum
  foo0,
  foo1,

proc main()=
  echo goo0.int
  # echo foo0.int # Error: undeclared identifier: 'foo0'
  echo int(foo0)

eg2:
same hijicking issue as mentioned in top post

This issue has been automatically marked as stale because it has not had recent activity. If you think it is still a valid issue, write a comment below; otherwise it will be closed. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings