-
Notifications
You must be signed in to change notification settings - Fork 38
add control.update(), which takes a partial control #65
Conversation
This allows developers to make a batch update to the entire control.
src/state/controls/Button.ts
Outdated
@@ -71,4 +71,11 @@ export class Button extends Control<IButtonData> implements IButton { | |||
public giveInput(input: IButtonInput): Promise<void> { | |||
return this.sendInput(input); | |||
} | |||
|
|||
public update(changedData: Partial<IButtonData>): Promise<void> { | |||
if (changedData.cooldown) { |
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.
IButtonData is documented as having its cooldown be a unix timestamp, here that is broken. Prefer to keep a single unambiguous representation for all data, providing utility methods as needed for fluent shortcuts.
Also, avoid mutating function input! This is a surprising side effect.
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 im trying to understand how to indicate that for this particular method that the cooldown should be a UTC whereas setCooldown takes a duration.
Could we perhaps use an extended interface here that has duration
to allow for this behavior?
Trying to make this make sense for everyone.
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 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'm not clear on the need to allow the method to take a duration at all.
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.
Ok, so:
before: "I want to set the button's text to "connor" and the cooldown to 5 seconds"
control.setText('connor').then(() => control.setCooldown(5))
After:
control.update({
text:'connor',
cooldown:<A utc what?>
});
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.
Connor, I want to enable batch updates as a utility method
I want to enable them easily. Control.update(..what you want to update)
=> Promise<void>
(or <IControlData>
) makes sense to me.
What doesn't is the cooldown. This is the only problem imo. As you initially were the one to update setCooldown
to take the inputed duration and change it into a timestamp I would like you advisement on how to do this. Within control.update
.
I do not see how creating a utility method that allows people to update multiple properties in the same service call breaks Liskov.
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.
Within control.update.
This is the issue, this is not possible while overriding the behavior of the cooldown
property. I mentioned above:
Control<T> has a method update(Partial<T>) while Button extends Control<R> while having a method update(Partial<X>)
The wikipedia page on the LSP lists:
Liskov's principle imposes some standard requirements on signatures... Contravariance of method arguments in the subtype.
Taking type X
where X
is not a supertype of R
breaks contravariance.
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.
Ok, so its the signature. let's change the signature: IControlUpdate, IButtonUpdate which we can document as having coolodwn in miliseconds. brb doing that.
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.
Corrected my above message, sorry for the mistype: X
must be a supertype of R
, R
can be a composition of X
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.
oK! :)
src/state/controls/Control.ts
Outdated
changedData.etag = this.etag; | ||
return this.client.updateControls({ | ||
sceneID: this.scene.sceneID, | ||
controls: [ changedData ], |
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.
rm spaces
src/state/controls/Control.spec.ts
Outdated
controlID: buttonData.controlID, | ||
}, | ||
buttonDiff, | ||
); |
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.
Prefer the spread operator to object.assign
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 prefer object.assign. Do you have a reason for its use over spreading?
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 guaranteed to be free of side effects, and is the standard we follow in all other TypeScript code/projects
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.
Eh spread works, im just used to assign from the old days. changing sec
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.
The way i used object.assign with the initial parameter of {} guarantees no side effects too.
@connor4312 I did a thing, with the new interface we actually prevent people shooting themselves in the foot too. |
Still outstanding comments (in Slack DM) |
src/state/controls/Control.ts
Outdated
@@ -104,9 +104,9 @@ export abstract class Control<T extends IControlData> extends EventEmitter imple | |||
/** | |||
* Update this control on the server. | |||
*/ | |||
public update(controlUpdate: IControlUpdate): Promise<void> { | |||
public update<T extends IControlUpdate>(controlUpdate: T): Promise<void> { |
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.
What is the point of this, T will always implement the interface so the statements are equivalent.
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.
Connor says this PR breaks Liskov so im trying to fix it.
src/state/controls/Control.spec.ts
Outdated
text: 'foobar', | ||
}; | ||
const updatedButton = { | ||
...{ |
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 need to spread an object on here, you can include the properties directly
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.
oh yes!
export interface IJoystickUpdate extends IControlUpdate { | ||
/** | ||
* Updates the angle of the Joysticks direction indicator. | ||
* In radians 0 - 2. |
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.
0 - 2π
surely?
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.
sure
This allows developers to make a batch update to the entire control.
Resolves #38