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

Abstract type members are incorrectly forbidden in objects (unless inherited) #8217

Closed
scabug opened this issue Jan 31, 2014 · 10 comments
Closed
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Jan 31, 2014

The behavior of Scalac (2.10.3) is inconsistent between objects WTF_A0 and A below: in one case an undefined type member is forbidden, in the other case it is allowed just because it is inherited.
-I speculate that forbidding abstract type members is not needed to ensure soundness, and allowing them also seems of dubious utility (but empty and distinct types are useful in Haskell in type-level programming).-
After clarifications: undefined type members can encode existential types, so they are allowed on purpose. The handling of WTF_A0 is a mistake.

I searched JIRA for "undefined type members" and found no relevant report. I can't find any applicable part of the spec describing the expected behavior.

//Interesting facts are noted with WTF throughout this snippet.
trait A {
  type T
}

//WTF??? We do not need to define abstract types ever?
object A extends A

//WTF? But if the declaration is not inherited, we do need to define abstract types?
object WTF_A0 {
  type T //only classes can have declared but undefined members
}

class WTF_A1 {
  type T //classes indeed can have an undefined type member. WTF?
}

object Test_WTF_A1 {
  new WTF_A1 //and we can even instantiate the class. WTF?
}

The behavior also seems unintentional: The code producing this warning (src/compiler/scala/tools/nsc/typechecker/Namers.scala:Namer.validate) does not seem to be specific to type members — it is generally related to contained symbol, and there is no comment describing why undefined inherited members should be allowed while they should be forbidden if declared inline.

@scabug
Copy link
Author

scabug commented Jan 31, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8217?orig=1
Reporter: @Blaisorblade
Affected Versions: 2.10.3

@scabug
Copy link
Author

scabug commented Jan 31, 2014

@retronym said:
This is basically a duplicate of #1753.

Previous discussion: https://groups.google.com/forum/#!topic/scala-user/MiKsvizQBd4

@scabug
Copy link
Author

scabug commented Jan 31, 2014

@Blaisorblade said:
#1753 is related and instructive, but incomplete. It only says that

class A { type T }

is intentionally allowed.

But what about objects? Why is the following forbidden?

object WTF_A0 {
  type T //Error: only classes can have declared but undefined members
}

I don't think that objects were indeed meant to be special.

Otherwise, the following should be also forbidden:

trait A {
  type T
}
 
object A extends A

If this inconsistency is by design, I'd demand more explanation than this:

I'm pretty sure it's been discussed before and it falls into the not-a-bug category.

Additionally, on the implementation level, the mere fact that the the check for undefined members is different from the check for undefined inherited members seem debatable — I guess the former can be done earlier, but it seems the two checks should still share logic.

@scabug
Copy link
Author

scabug commented Jan 31, 2014

@retronym said:
Related: scala/scala#3407

@scabug
Copy link
Author

scabug commented Jan 31, 2014

@Blaisorblade said (edited on Jan 31, 2014 7:06:26 PM UTC):
Adriaan seems to agree in this pull request: scala/scala-dist#127. I'm trying out the patch below, it does what I want, need to check for regressions. Before:

$ scala
Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51).
scala> object Foo {type A}
<console>:7: error: only classes can have declared but undefined members
       object Foo {type A}
                        ^

After:

$ ./qbin/scala
Welcome to Scala version 2.11.0-20140131-194308-ea897b018a (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51).
scala> object Foo {type A}
defined object Foo

Fix:

--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -1617,6 +1617,7 @@ trait Namers extends MethodSynthesis {
         def symbolAllowsDeferred = (
              sym.isValueParameter
           || sym.isTypeParameterOrSkolem
+          || sym.isAbstractType
           || context.tree.isInstanceOf[ExistentialTypeTree]
         )
         // Does the symbol owner require no undefined members?

I'm also wondering about extending the check to concrete classes, while at it, since the reimplementation of these checks in refchecks is not run by the presentation compiler:

@@ -1623,7 +1624,8 @@ trait Namers extends MethodSynthesis {
         def ownerRequiresConcrete = (
              !sym.owner.isClass
           ||  sym.owner.isModuleClass
           ||  sym.owner.isAnonymousClass
+          ||  sym.owner.isConcreteClass
         )
         if (sym hasAnnotation NativeAttr)
           sym resetFlag DEFERRED

@scabug
Copy link
Author

scabug commented Feb 3, 2014

@Blaisorblade said:
I had forgot to link the pull request: scala/scala#3442.
(I let go of the second change I mentioned because things are not as easy, and I keep getting strange unexpected failures on it. Also, it's not related to this bug anyway).

@scabug
Copy link
Author

scabug commented Feb 5, 2014

@paulp said:

If this inconsistency is by design, I'd demand more explanation than this:

I'm pretty sure it's been discussed before and it falls into the not-a-bug category.

You and your wild ambitions. Once you're properly calibrated you will see that is an unusually clear and complete specification.

@scabug
Copy link
Author

scabug commented Feb 11, 2014

@Blaisorblade said:
I understand your point, but this is going to get fixed, and the clarification to the spec is already agreed on: scala/scala-dist#127

Now, it would be cool if somebody would explain the world the point of undefined type members more clearly (answer: they encode existentials), but I certainly can't explain that undefined type members are allowed as long as this bug is not fixed.

@scabug
Copy link
Author

scabug commented Feb 15, 2014

@adriaanm said:
Yes indeed! We fixed the spec before the compiler. I agree with the intent of the PR, but it needs some polish.
If we're going to allow abstract type members in classes, we should also allow them in objects, especially since they are already indirectly allowed by extending such a class.

@scabug
Copy link
Author

scabug commented Nov 7, 2015

@Blaisorblade said:
This was fixed in scala/scala#4024, time to close :)

@scabug scabug closed this as completed Nov 7, 2015
@scabug scabug added this to the 2.11.3 milestone Apr 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants