#ask How should we improve Motoko?

@jzxchiang, actually, imperative data structures are compatible with stable variables. What isn’t are object-oriented abstractions, because of the functions embedded in the data. But that is an independent dimension, as objects can be either imperative or functional.

To wit, here is a toy example of a counter object that, although functional, cannot be put in a stable var:

class Counter(x : Nat) {
  public func get() : Nat { x };
  public func inc() : Counter { Counter(x + 1) };
};

stable var c : Counter = Counter(0);   // ERROR

On the other hand, here is an imperative counter type that you can store in a stable var just fine:

type Counter = {var count : Nat};
func Counter(x : Nat) : Counter { {var count = x} };
func get(c : Counter) : Nat { c.count };
func inc(c : Counter) { c.count := c.count + 1 };

stable var c : Counter = Counter(0);  // ok

Of course, that doesn’t eliminate the dilemma, but it is rather between choosing object-oriented and “procedural” interfaces.

2 Likes

Right, but once you loosen it like that, the intent is no longer visible in the code. It might or might not be an accident.

In my experience (e.g. in OCaml), the strict rule is good documentation and uncovers many mistakes early on. The occasional ignore in cases like replace is a fair deal in exchange. But like option types, it’s one of these features that you have to learn to “hold right”. When you are working against it (perhaps out of habit) you can end up with repetitive strain injury.

2 Likes

I don’t want to be deciphering the documentation.

What I need :slight_smile:

What I get :frowning:

Also, Add a “New developper start here” button with Dr Angela Yu uDemy Web3 video featuring ICP and Motoko. Would have save me a ton of hours searching for basic info as a newbie.

5 Likes

We 100% should have a https://embed.smartcontracts.org/ example for each of the functions in base.

4 Likes

That’s a really good idea…

I’ll build an MVP to show the team, and we’ll see what happens from there.

3 Likes

It’d be cool if we could omit optional record fields.

Screen Shot 2022-11-07 at 9.47.56 PM

6 Likes

That’s ends up creating a totally different type and reworking the meaning of an optional type into something more JavaScripty though, right?

You can always narrow

  type OptionalArgsABC = { a : ?Text; b : ?Text; c : ?Text };
  let optionals : OptionalArgsABC = { a = ?"maybe"; b = ?"is"; c = null };

  type OptionalArgsAB = { a : ?Text; b : ?Text };
  let { a; b }: OptionalArgsAB = optionals;

@tomijaga What’s the common use case you have in mind?

2 Likes

@icme Lets say we have a method that accepts parameters as the first argument

public shared func myMethod(params: {
  paramA: ?Nat;
  paramB: ?Nat;
  paramC: ?Nat;
  paramD: ?Nat;
  paramE: ?Nat;
})

All of the parameters are optional. I want to call this method, but I only need to pass paramA

myMethod({ paramA = ?1; paramB = null; paramC = null; paramD = null; paramE = null });

Not very convenient as I still need to specify all of the parameters even if I don’t need them. With the latest features, though, I can do this

let defaultParams = { paramA = null; paramB = null; paramC = null; paramD = null; paramE = null };

myMethod({ defaultParams with paramA = ?1 });

A lot better but still requires defaultParams to be declared on the side of a caller

4 Likes

I could see this as a good class constructor scenario as well.

Record extension syntax works for now, but at least that is explicitly saying what the defaults are - it sounds like with this feature you’d like the defaults to implicitly be null.

3 Likes

some better vscode tooling would be really nice

1 Like

@ZhenyaUsenko explained the use case I had in mind.

Yes, that is right.
I was thinking about the user experience when calling a function that takes a record with many optional fields.
An example would be initializing the ICRC-1 token, where some fields are optional and have default values set, so they don’t need to be specified by the user.
This was the Initial type, but I updated it later to the one below because there were too many optional types.

        let token = Token.Token({
            ... 
            min_burn_amount: ?Nat;
            minting_account: ?Account; 
            permitted_drift: ?Nat;
            transaction_window: ?Nat; 
            burned_tokens: ?Nat 
        });

I moved the fields least likely to be specified by the user into an optional record called advanced_settings.

        let token = Token.Token({
            ... 
            min_burn_amount: Nat;
            minting_account: ?Account; 
            advanced_settings: ?{
                permitted_drift: Nat;
                transaction_window: Nat; 
                burned_tokens: Nat;
            };
        });

Also, it seems like motoko supports this functionality for serializing partial records encoded in candid.
https://m7sm4-2iaaa-aaaab-qabra-cai.raw.ic0.app/?tag=965353562

2 Likes

Hey @nolyoi, what types of tools are you referring to?

Also, are you aware of the vscode extension the dfinity team is working on?

3 Likes

Auto generated CLI args. For example you write this function:

public shared func registerUser(handle : Text, displayName : Text) : () {
...user registration
return
}

Then we could run a dfx command to generate an example command line argument, dfx canister call Canister1 registerUser --example-cli-arg, which could return:

dfx canister call Canister1 registerUser '("handle" : text, "displayName" : text)'

1 Like

This is actually supported. You can use dfx canister call Canister1 registerUser --random '' to generate a random value of that type. You can even customize the random value, e.g., use --random '{text = Some "name"}' to generate a random name. The spec of the random config is here: candid/config.md at master · dfinity/candid · GitHub

7 Likes

The Motokodoc is great. Is it possible to have auto-generation/snippet hotkey that fills out each part of a function’s signature as a template? And then an option to hide all unless on hover/specifically selected?

Might be worth autolinking to the corresponding comments in the Candid file as well.

2 Likes

Great idea! I’ll add some doc comment snippets right now.

Here’s the source file in case anyone is interested in contributing code snippets to the VS Code extension and Motoko Playground:

1 Like

I have no clue what this is…what does this do and how do you use it?

1 Like

Avoid await when multi-container cascading queries, multi-level query waiting gives the front-end user a very poor experience.
For example container A, B
The queryinfo function of the B container is called in the A container

// ideal situation
     public shared query func moreInfo() : async Text {
             B. queryinfo();
     };

// Current situation
     public shared func moreInfo() : async Text {
             await B. queryinfo();
     }

Is there a current or planned solution for this?

1 Like

Idk if that is the accepted term, but it’s the equivalent of Javadoc.

Originally I learned about it while looking through the invoice canister code: examples/main.mo at kyle/invoice-canister-cleanup · dfinity/examples · GitHub

  // #region get_account_identifier
  /*
    * Get Caller Identifier
    * Allows a caller to the accountIdentifier for a given principal
    * for a specific token.
    */
  public query func get_account_identifier(args : T.GetAccountIdentifierArgs) : async T.GetAccountIdentifierResult {

It will make it so hovering over these fields will show a tooltip that looks like (similar method but with additional formatting used):

I found it very useful when first working with the code, and as not as known as Motoko is every bit helps. To add such a comment, start with a /** and end with a */ where the ending */ must be directly above the field declaration (no vertical line spaces). In the snippet above the opening double asterisk can be separated, but I found that the beginning * of each line of comment will also appear in the tooltip.

Syntax I know of so far:

  • the Markdown linking syntax works “[“desc”]”(url)
  • trigger a new line with a \ as the very last character of the current line (no additional white space)
  • terminating a line with double white space will also trigger a new line
  • Double asterisk for bold
  • Single asterisk or underscore for italic
  • code enclosed as back tick marks `
  • The @ sign did something once but I don’t remember what specifically triggered it

If the Motokodoc is one line, I personally like to use:
/**** <One Line Comment Title Text> ***/
to emphasis it as a header.

I’ve been using 80 character spaces before making a new line (since the tool tip won’t autowrap), but maybe the modern max-width convention is 120 chars?

One thing to note is that the \ new line character isn’t escaped when moc doc is used (at least for html output) which is another task to do.

Finally I mentioned that if it would be possible it might be useful to link one field’s Motokodoc into another, so for instance “non-trivial” Result.Result types could automatically show their Success and Error types if (also defined) and linked. Or equally useful would be a way to import the corresponding did field’s comments, since that’s supposed to be the source of truth about a canister for external callers, and much of the info would likely be the same.

2 Likes

Maybe there is a way to do this already, but how about “pretty print” for debug_show output in the console–specifically formatting for nested types (like records in variants in records, etc)?

1 Like