Skip to content
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

Improve CircuitValue #269

Merged
merged 10 commits into from
Jul 7, 2022
Merged

Improve CircuitValue #269

merged 10 commits into from
Jul 7, 2022

Conversation

mitschabaude
Copy link
Collaborator

@mitschabaude mitschabaude commented Jun 30, 2022

this makes significant changes to the CircuitValue class, some non-controversial and some potentially controversial:

  • change the types of static methods on CircuitValue -- they weren't inferred correctly before, now they are, so type-safe extending of these methods works now
  • might be controversial: make the constructor on CircuitValue generic.
    • the benefit is that now users of CircuitValue don't have to write a (very boiler-plate-y) constructor.
    • a downside is that, with default TS configs, people not using a constructor on classes that extend CircuitValue will get a TS error on their props:
      "Property has no initializer and is not definitely assigned in the constructor"
      this can be fixed locally by adding a ! to the prop, e.g. @prop value!: Field. it can also be fixed globally in the project by adding a TS config option, which we should probably do in the CLI template project
    • another small downside is that overriding the constructor becomes a bit more error-prone - you have to pass on your constructor arguments to super(). as such, this change probably breaks a couple of existing code, in a way that fixing it might not be very obvious. if we go with this, I think going forward we should not encourage the pattern of overriding the constructor in examples, but instead add static from methods which add any additional logic and invoke the original constructor. e.g., see how I changed the sudoku example

Copy link
Collaborator Author

@mitschabaude mitschabaude left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comments:

abstract class CircuitValue {
constructor(...props: any[]) {
Copy link
Collaborator Author

@mitschabaude mitschabaude Jun 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fun fact: this function was written verbatim, completely correctly, by github copilot on the first try!!!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's pretty amazing!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is really cool! I'm going to try out copilot.

@@ -122,21 +166,6 @@ abstract class CircuitValue {
}
}

(CircuitValue as any).check = function (v: any) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was able to remove this hack because I got the types working on CircuitValue

super();
this.magnitude = magnitude;
this.sgn = sgn;
super(magnitude, sgn);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left this constructor because it adds something nice -- a default value for one of the arguments

@@ -14,6 +14,7 @@
"useDefineForClassFields": false, // ensure correct behaviour of class fields with decorators

"strict": true, // for the full TypeScript experience
"strictPropertyInitialization": false, // to enable generic constructors, e.g. on CircuitValue
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we go with this PR, this should be added in the zkapp CLI template projects as well

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @ymekuria has a heads up 👀

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should fix this globally in the CLI and push users to do the same instead fixing locally by adding a ! to the prop, e.g. @prop value!: Field.

@@ -84,6 +83,7 @@ class SudokuZkapp extends SmartContract {

// finally, we check that the sudoku is the one that was originally deployed
let sudokuHash = this.sudokuHash.get(); // get the hash from the blockchain
this.sudokuHash.assertEquals(sudokuHash);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a fix that's unrelated to the rest of the PR

Copy link
Contributor

@MartinMinkov MartinMinkov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good to me as long as everyone agrees on this controversial change :D

I added an issue in the zkapp-cli repo to update the Sudoku example if this lands in it's current state.

const value = (v as any)[key];
if (propType.check === undefined)
throw Error('bug: circuit value without .check()');
propType.check(value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this error get thrown if a CircuitValue class does not define a check function for itself?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no! it would get thrown if one of our primitives was missing check -- which isn't the case --, or maybe if a developer uses something which isn't a CircuitValue,

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but probably won't get thrown at all :D

abstract class CircuitValue {
constructor(...props: any[]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's pretty amazing!

Copy link
Contributor

@ymekuria ymekuria left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes LGTM assuming we all decide to accept the controversial changes. I added an issue to the CLI similar to @MartinMinkov 's to update the TS Config if this PR lands.

I generally like this approach of reducing boilerplate in the constructor for users. The TS error downside is minimal and can be mitigated fairly easily. Introducing a new pattern of adding a static from method will be more involved. It would involve changing existing code, updating docs, and user eduction. I think the upside is probably worth all this.

@mitschabaude
Copy link
Collaborator Author

mitschabaude commented Jun 30, 2022

Introducing a new pattern of adding a static from method will be more involved. It would involve changing existing code, updating docs, and user eduction. I think the upside is probably worth all this.

Hmm ok, we also don't have to do this. If you don't prefer it then we can also stick with constructors in our examples, or just don't single out one way of doing it

@ymekuria
Copy link
Contributor

Introducing a new pattern of adding a static from method will be more involved. It would involve changing existing code, updating docs, and user eduction. I think the upside is probably worth all this.

Hmm ok, we also don't have to do this. If you don't prefer it then we can also stick with constructors in our examples, or just don't single out one way of doing it

I'm ok to do this if we all agree that this pattern is better. We should be clear and consistent on our recommendations of best practices.

Copy link
Member

@bkase bkase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, I think the tradeoffs are all worth it 💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants