-
Notifications
You must be signed in to change notification settings - Fork 30
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
Outer sends need to check both super classes and mixins #189
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no idea whether the code is correct, haven't even tried to think about it. Sorry.
But, it looks good :)
Just some minor things.
Not sure what's going on with CI, we might need to update mx to get it working first. Would be worth a try.
@@ -0,0 +1,54 @@ | |||
(* Copyright (c) 2001-2017 see AUTHORS file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't like: https://github.com/smarr/SOMns/blob/master/core-lib/TestSuite/MixinTests.ns ?
Please place the tests next to the existing ones.
Please also check whether this resolves any of the issues with the currently deactivated tests in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've examined the deactivated tests. Some success - two are fixed, three remain broken. Out of the three broken tests:
- (testConflictingSlotsImmutable) I don't understand which answer is correct
- (TestInitializer1) A slot (that should exist) is not found. Unsure how to debug
- (TestInitializer3) I don't whether a class resulting from a mixin application be able to access mixed in methods annotated as private?
Some more details below:
testConflictingSlotsImmutable - Broken
c
is an instance of ConflictingSlotsImmutable, a class that inherits from Object and applies a mixin X that declares a public slot x. The initer method for ConflictingSlotsImmutable defines a new public slot x with initer expression x = 1.
After the initer method runs, x
is equal to 1
. The test asserts that slot x
is nil. I'm unsure which answer is correct.
testConflictingMethods - Fixed
c
is an instance of ConflictingMethods, a class that inherits from Y
and applies a mixin Y2
. Both Y
and Y2
define a method foo
. The test now passes with the correct result (Y2
's foo wins).
TestInitializer1 - Broken
c
is an instance of C
, which inherits from object and applies mixins X (first) and X2
(second). Both X
and X2
define a public slot x
with an initer expression. SOMns throws an assertion in this case (of which I'm unsure how to debug):
java.lang.AssertionError
at som.vmobjects.SObject.getLocation(SObject.java:485)
at som.vmobjects.SObject.writeSlot(SObject.java:509)
TestInitializer2 - Fixed
c
is an instance of C
, which inherits from object and applies mixins X
(first) and X2
(second). Both X and X2 define a public slot x
. Both X
and X2
define an initer that assigns x
a different number. The test now passes with the correct result (X2
's initer wins).
TestInitializer3 - Broken
c
is an instance of C
, which inherits from object and applies mixins X
(first) and X2 (second). X
defines a private method cnt
and X
's initer method uses this variable to set a public field x
. When the tests runs, c
does not understand the message cnt
.
Should a class resulting from a mixin application be able to access mixed in methods annotated as private?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should a class resulting from a mixin application be able to access mixed in methods annotated as private?
This is a question for the spec. I don't know by hard, but I would suspect so.
About the slot related issues. I won't be able to dive into that at the moment, so, let's just ignore those for now. Except if you need that to work for Grace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's ignore it for now. The current implementation is at least a step in the right direction (at least, its sufficient for Grace since I won't use slots at the moment). I'd be happy to readdress the slot issues next month and make any changes to fix up three tests that remain broken.
@@ -87,6 +87,9 @@ public boolean isSuperSend() { | |||
|
|||
protected final SClass getEnclosingClass(final SObjectWithClass rcvr) { | |||
SClass lexicalClass = rcvr.getSOMClass().getClassCorrespondingTo(mixinId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is silly nitpicking, but, I just had issues reading this code, so, could we use a rcvrClass
local variable?
Then we also avoid twice the .getSOMClass()
. Not that it matter performance-wise, but I have to think of one indirection less.
@@ -120,6 +121,15 @@ public boolean hasOnlyImmutableFields() { | |||
return superclassAndMixins; | |||
} | |||
|
|||
public boolean isBasedOn(final MixinDefinitionId mixinId) { | |||
for (SClass cls : getSuperclassAndMixins()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a call to VM.callerNeedsToBeOptimized("Result of isBasedOn should be cached")
before the loop?
@@ -120,6 +121,15 @@ public boolean hasOnlyImmutableFields() { | |||
return superclassAndMixins; | |||
} | |||
|
|||
public boolean isBasedOn(final MixinDefinitionId mixinId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a comment what the semantics of this now is?
src/som/vmobjects/SClass.java
Outdated
@@ -173,7 +173,7 @@ public void initializeStructure(final MixinDefinition mixinDef, | |||
// assert instanceClassGroup != null || !ObjectSystem.isInitialized(); | |||
} | |||
|
|||
private boolean isBasedOn(final MixinDefinitionId mixinId) { | |||
public boolean isBasedOn(final MixinDefinitionId mixinId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, could you add a comment what the semantics of this now is?
(not yet awake, and I haven't read this code in ages, so not sure what I was thinking here back then. sorry)
src/som/vmobjects/SClass.java
Outdated
@@ -204,6 +204,16 @@ public SClass getClassCorrespondingTo(final MixinDefinitionId mixinId) { | |||
return cls; | |||
} | |||
|
|||
public SClass getClassWithMixinCorrespondingTo(final MixinDefinitionId mixinId) { | |||
VM.callerNeedsToBeOptimized( | |||
"This should not be on the fast path, specialization/caching needed?"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:) 👍
src/som/vmobjects/SClass.java
Outdated
@@ -204,6 +204,16 @@ public SClass getClassCorrespondingTo(final MixinDefinitionId mixinId) { | |||
return cls; | |||
} | |||
|
|||
public SClass getClassWithMixinCorrespondingTo(final MixinDefinitionId mixinId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I don't like the name.
If I ask clazz.getClass*()
, I think I expect the class of the class with some property.
How about just getMixin(..)
?
Also see my comment for getClassCorrespondingTo()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getClassWithMixinCorrespondingTo
returns the receiver class or one of its superclasses (not the mixin's class). The class returned is that one who has had the given mixin applied. For example if we have an class C
defined as:
Mixin = class()()
B = class Object <: Mixin ()()
C = class B ()()
Then the result of C. getClassWithMixinCorrespondingTo(Mixin)
is B
, because the mixin was applied to B
. Does that make sense? Do you have a suggestion for the method name, given this example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, let's just talk about the java level and the naming, not the functionality on the language level.
The first thing that getClassWithMixinCorrespondingTo(.)
can return is this
(line 210).
The name of the method does not make me expect that.
If I ask any object in Java this.getClass()
, I'll never get this
returned, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps the get is bad. Perhaps what this is here is actually a lookup.
Perhaps just lookupClass(mixinId)
?
src/som/vmobjects/SClass.java
Outdated
} | ||
return cls; | ||
} | ||
|
||
@ExplodeLoop | ||
public SClass getClassCorrespondingTo(final int superclassIdx) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I suppose you were just following my example? Well, looks like i changed my mind here, didn't I?
Hmmm, well, don't know. The CorrespondingTo
seems superfluous. Maybe it isn't.
Ok, I'll leave it up to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that CorrespondingTo
is not needed. I will remove. See my previous comment regarding the naming for getClassWithMixinCorrespondingTo
and we we can go from there.
Looks like the CI issue was temporary. |
I've adapted the PR to meet the requested changes. I'm not sure that I've done a great job of the new docstrings (ClassFactory.isBasedOn, SClass.isBasedOn, and OuterObjectRead.getEnclosingClass). Please review before accepting! |
- publicized access to SClass.isBasedOn() - added isBasedOn method to ClassFactory - outer object read now checks both classes and mixins - renamed method for looking up class
- added test where mixin invoke outer method - added test where mixin accesses outer slots
As you might have seen, I just briefly checked for the expected behavior with the Newspeak experts. Just to avoid reading the spec carefully, I suppose 😆 I also compress the history a bit. Seemed useful to have the reason for the refactorings in the same commit. But, I probably have a different opinion on it every day... Will merge once CI passed. |
Signed-off-by: Stefan Marr <git@stefan-marr.de>
Classes created via mixin application should preserve access to variables and methods bound in enclosing scopes.
Before these changes classes created via mixin application were not able to preserve this access; in particular, SOMns would fail to specialize
ResolvingImplicitReceiverSend
when one of the applied mixin's methods accessed something defined in its enclosing activation.For example in the following program (before these changes) SOMns would fail to specialize the implicit request for
bar
(from insideA.foo
):These changes enable SOMns to correctly resolve implicit requests when made by the methods of an applied mixin. In particular, logic has been added to
OuterObjectRead.getEnclosingClass(MixinDefinitionId)
to make this possible. As before, each super class (from shallowest to deepest) is checked to see if it matches the parameterMixinDefinitionId
. If no viable super class is found, then each of the mixin's applied to each super class (again from shallowest to deepest) are checked to see if they match the parameterMixinDefinitionId
. In both cases, the first superclass to meet the condition is selected as the class who should resolve the outer read.With the above changes, SOMns is able to recognise that the
B
contains within it a mixin that is based onA
and, consequently, can specialize the implicit request forbar
withB
as the receiver. Therefore, with these changes SOMns can preserve access to variables and methods bound in enclosing scopes for the methods of applied mixins.