Closed kjx closed 6 years ago
See also #32 and #59. Back in 2015, Andrew thought required methods should be optional (https://github.com/gracelang/language/issues/32#issue-106885595). I can't see anything in the spec saying whether required methods are required or are optional.
Another way to put this is the question of whether the resolution of an internal request (implicit request), that, according to the current spec
"must resolve to one of the former cases"
(i.e. a self
or an outer
request)
must be manifest (resolved early) or can be resolved late?
Kim (https://github.com/gracelang/language/issues/59#issuecomment-186087713) once suggested that "If a construction introduces an error that cannot be fixed, then it should be declared erroneous at that point".
Things like missing required methods, some (all?) structure clauses, etc, can actually always be "resolved later" provided the class with the problem is abstract, and provided concrete subclasses always fix the problem. The example at the top of this issues has he sup
class with a "missing abstract method" error, and its subclass sub
resolves that problem by defining the method.
I have a vague memory of a discussion where (I believe) there was some agreement that in the example above, we would need to write
method y {required}
or similar syntax, but that one could create an object from sup that would work fine as long as there was no call of y. The static typing discipline would most likely bar creation of an object from such a class, but a more dynamic version would allow the creation so you could test the methods as they are (slowly) added.
I don't recall that we ever discussed labeling classes/objects as "abstract".
I so agree that there should be no difference between calling y and self.y if the former is resolved to a call of self.
I have a vague memory of a discussion
me too.
but I also thought we were switching back to abstract
as the keyword.
(At this point, I'd dump conceptual purity and make it an annotation that requires a null method body)
but that one could create an object from sup that would work fine as long as there was no call of y
as you said somewhere else I can't find - the problem with allowing the dynamic interpretation is we have to provide semantics for it. In this case that's not really a problem. (actually, the "core Grace" I have in my head is so simple that in most cases the semantics aren't really a problem, which makes we wonder why we necessarily restrict things).
I don't recall that we ever discussed labeling classes/objects as "abstract".
we didn't - I recall an old discussion thinking that we couldn't - if we could annotate objects then we could.
I so agree that there should be no difference between calling y and self.y if the former is resolved to a call of self.
aye ,there's the rub. How do you know if y
means the same as self.y
?
I think the answer is - you know by manifest
but manifest
breaks modularity (see Gilad).
Another answer is: you know y
must mean self.y
if y
couldn't mean outer*.y
and you can pretty much always know that given a module and its dialect. Inheritance can cross module boundaries.
the only possible way to make progress is to adopt the minigrace design
should this code "compile" - and more importantly, why?
amg give a compiles time error at line 2, saying "unknown variable or method 'y'". Kernan crashes at runtime with "No receiver found for y". Why? Where does it say so in the spec? Which behaviour should be mandatory for all implementations, or option (i.e. could be in a dialect)?
I seem to remember a discussion that this kind of program should be OK if everything was untyped.
Both Kernan & amg will accept and run a program where line 2 becomes
method x {self.y}
. Why?. I can (sort of) see why that should be acceptable, again especially in a untyped context, but don't see why the implicit send version above should not also be acceptable. At this point, we have all the lexical context forsup
so we knowy
is not defined in an outer lexical scope. We also know (in this example, for sure) thaty
is not defined in a superclass ofsup
(there isn't one) but of coursey
could be defined in a subclass, indeed, here it is defined insub
.Perhaps
y
should be defined asrequired
insub
- but if it isn't, why is writingself.y
OK but just 'y' is not? and where is that distinction defined?Finally, here's the complementary program:
Both amg and Kernan accept this at compile time but crashes with a runtime error. if we want any of these kind of things to be a "compile" error - shouldn't it be this one? we can be absolutely sure (modulo linking to different version of a dialect) that
y
is NOT anywhere in theouter
of sup. (see also #59 #102)