Closed kjx closed 8 years ago
I think that they have to be evaluated in the surrounding scope. They clearly can't, for example, request methods on self, since neither self not its methods exist at the time the inherits and uses statements are evaluated.
It would make sense to locate these clauses outside the braces that demarcate the object's scope, except that in a module, there are no braces and there is no outside.
Regardless of what syntax we adopt for a manifest constant, such a constant also will beed to be evaluate in the surrounding scope.
Unfortunately, this gets very complicated very quickly. Do we allow the keyword self to appear in an inherits statement? If so, does it mean the current object (which would be an error), or the surrounding object, which would be ok, but surely confusing. If we don't allow self, what is the right way to refer to the outer object? outer? But if we say that inherits is evaluated in the surrounding scope, then shouldn't outer mean the outer's outer?
This is really horrible.
I suggest no restrictions, but a strong warning (in the reference manual and perhaps a warning message emitted by the compiler) that it is evaluated in the outer scope. Only an idiot programmer would use self in the inherits, but, hey, we let idiots do all sorts of strange things. I think our notion of nested classes/objects leads to some complexities that other languages avoid, but most will use them with care (I hope!)
It would make sense to locate these clauses outside the braces that demarcate the object's scope
well perhaps we should move them out.
except that in a module, there are no braces and there is no outside.
Modules are already special. You can only have imports at the top level. We could allow inherits/uses clauses inside modules without breaking everything.
Arguably the names introduce by "import" needs to go into an additional scope sandwiched between the dialect and the main module scope. We could run module inherits clauses in that scope too.
You can only have imports at the top level.
If so, we should put that in the spec!
The idea that modules are just objects, but objects that are named by a extra-language mechanism, was one of the great insights of Grace's design. Let's not spoil it by making too many differences between modules and other objects.
Saying that imports must be at the top-level is OK. Changing the syntax is not.
Changing the syntax is not.
why not? #61
I think there is an argument that *inconsistent syntax between modules & object constructors is problem --- but as above I argue they are already inconsistent because the object { } is omitted for modules. That said: I can see an argument that modules could be "the body of an object { } constructor, prepended with import statements" --- arguing in favour of keeping the inheritance/uses clauses inside that body. On the other hand, if the arguments to those statements are executed in the surrounding scope, that breaks another principle, that "things are executed where they appear".
So we have to choose.
Rather than saying that inherits is executed in the surrounding scope, we could say that the inherited value cannot refer to anything declared in the current scope. This is subtly different! For example, rather than changing the meaning of self, it says that we can't utter self, and that outer in an inherits statement means the immediately enclosing object, as one would expect, and not the second-outermost enclosing object.
(dunno why I can't see this on github (yet?)
On 8/03/2016, at 9:02am, Andrew Black notifications@github.com wrote:
No, because that would give outer a counter-intuitive meaning. We should say that parent expressions can't refer to self, implicitly or explicitly. We also need to say that parent expressions are manifest,
we do:
The argument of an inherit or use clause is restricted to be a Manifest Expression that creates a new object, such as a request on a class or trait. The argument cannot refer to self, implicitly or explicitly. The object reused by a use clause must be a trait object.
which may imply that they can't refer to self, if we pick a reasonable definition of manifest.
manifest currently also stops implicit self.
I added some consequent discussion to #67
cheers
James
Maybe I’m confused here, but I don’t see why parameters (either regular or type) to a class used in an inherits clause have to be manifest.
If I define:
class sup
def x = o.m(73) // o may itself have been passed in from elsewhere
class sub
then sup is certainly manifest in the inherits clause, but rg is not. Similarly, the value of x is certainly not manifest, yet can be used in the inherits clause.
[My earlier suggestion of anything from the outer scope being OK wasn’t quite right either, because rg isn’t technically in the outer scope, but hopefully you know what I meant.]
I’m also not certain why you would want type parameters to be manifest either. If I am defining a list of T, it’s not uncommon to want to define a subclass with some extra features (e.g., a length method). You want to keep this as a parameter that can be matched with the one from the superclass.
On Mar 7, 2016, at 12:02 PM, Andrew Black notifications@github.com wrote:
Should we just say these expressions are evaluated in the surrounding scope?
No, because that would give outer a counter-intuitive meaning. We should say that parent expressions can't refer to self, implicitly or explicitly. We also need to say that parent expressions are manifest, which may imply that they can't refer to self, if we pick a reasonable definition of manifest.
— Reply to this email directly or view it on GitHub https://github.com/gracelang/language/issues/68#issuecomment-193425581.
Can we talk about that at #47
58 contains some nasty examples of using self in use or trait clauses.
Should we just say these expressions are evaluated in the surrounding scope?