-
-
Notifications
You must be signed in to change notification settings - Fork 9
react: Add new exercise #20
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
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.
this was a very ambitious choice for the sixth exercise to be added to this track, and it might have been too ambitious.
There are ideas I feel like I don't yet know how to express well in the language, so it may pay well to try porting some different exercises first, shelving this attempt.
I sent this PR so that I have a record of the work, I can comment it on where I had troubles, and maybe others will help. I'll see what happens.
variable Element currentValue_; | ||
Element() newValue; | ||
|
||
shared new single(Cell c, Element(Element) f) { |
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.
here I had a hope that a call Reactor<Integer>.ComputeCell.single
would be able to treat this Element(Element)
as Integer(Integer)
, but it does not currently seem this is true.
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.
Because it was not true, I was forced to give up making this generic. Now our reactor only acts on Integers.
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.
update: given Element satisfies Object
was necessary.
shared new single(Cell c, Element(Element) f) { | ||
c.addDependent(this); |
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 not legal.
My alternatives are:
- create a different function on
Reactor
that constructs a compute cell then adds it as a dependent of its dependencies. I was afraid it would be unidiomatic to expose this constructor-that-isn't-a-constructor, but perhaps it is not so bad. - do it a different way, do not let cells know about their dependencies (why do I do it this way? only because it's the way which I did it in other language)
- force the caller to add the just-constructed
ComputeCell
as a dependent of its dependencies. I don't find this a reasonable interface.
newValue = () => f(c.currentValue); | ||
currentValue_ = newValue(); | ||
} | ||
|
||
shared new double(Cell c1, Cell c2, Element(Element, Element) f) { | ||
c1.addDependent(this); |
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.
also illegal.
newValue = () => f(c.currentValue); | ||
currentValue_ = newValue(); | ||
} | ||
|
||
shared new double(Cell c1, Cell c2, Element(Element, Element) f) { | ||
c1.addDependent(this); | ||
c2.addDependent(this); |
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.
also illegal.
closing to prevent accidental merges, but thoughts still appreciated. |
Okay, guess I have to make it so that the reactor is in charge of constructing. |
18780f4
to
1b90337
Compare
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.
a little unsure if I should keep all the value
in the tests (lets students be a bit more flexible with types if they can find a way to) or explicitly specify types (to make sure the types are as we expect)
|
||
alias Element => Integer; | ||
|
||
class Reactor() { |
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.
in this example solution, the reactor is absolutely useless; it does nothing. But I wanted to leave it in case a student's implementation truly needs it (for example, they store all their cells in an array and iterate over the array to propagate values)
shared actual Element currentValue => currentValue_; | ||
|
||
variable Integer callbacksIssued = 0; | ||
variable MutableMap<Integer, Callback> activeCallbacks = HashMap<Integer, Callback>(); |
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.
ouch, a bit of repetition here.
} | ||
} | ||
|
||
shared ComputeCell newComputeCell1(Cell c, Element(Element) f) { |
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.
#20 (comment) explains why Reactor
must be in charge of creating new compute cells - notice the addDependent
call on the newly-created cell. If this was done in an ComputeCell
initialiser, it will leak a reference to this
, which is illegal.
return cell; | ||
} | ||
|
||
shared ComputeCell newComputeCell2(Cell c1, Cell c2, Element(Element, Element) f) { |
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.
#20 (comment) explains why
Reactor
must be in charge of creating new compute cells - notice theaddDependent
call on the newly-created cell. If this was done in anComputeCell
initialiser, it will leak a reference tothis
, which is illegal.
same.
} | ||
} | ||
|
||
shared InputCell newInputCell(Element initialValue) { |
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.
it's not strictly necessary to delegate the creation to a Reactor
, but it is consistent with newComputeCell*
functions, which are necessary because of #20 (comment).
} | ||
|
||
test | ||
void removingCallbackMultipleTimesDoesntInterfereWithOtherCallbacks() { |
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.
there was supposed to be another test saying that callbacks can be removed - where did it go??????
(I'll add it back, just puzzled at how it could have disappeared from under my nose)
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.
Added back.
I'd like to go back to being able to say |
ah very interesting, it is at this very point where I run into:
I wonder why this is. I may have to defer on this, merge it as it is now, and try again later. |
Annotating the functions passed-in makes it work. |
It pleases me more (since it seems more idiomatic Ceylon, though what would I know?) to provide this cleaner interface to students, though it complicates the implementation a bit. I will see if there is anything else that can be done. |
Argh, we have to annotate types of all the compute functions now!!!
Inner inner; | ||
|
||
shared new single(Cell c, Element(Element) f) extends Cell() { | ||
// Since `c.addDependent(this)` is illegal, we have to create an inner cell. |
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.
for the record, I understand why it's illegal (if you give someone access to your this
before you've initialised, they can reference one of your uninitialised field, which is unsafe)
Final answer. |
I highly recommend squashing these commits before merging, because the intermediary WIP commits do not necessarily build and are not reflective of a complete exercise.