#ask How should we improve Motoko?

@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

Cascading message replies cause delays that add up, that is true. But that is inherent in the message-based architecture of the IC, not something Motoko can change.

1 Like

My understanding is that composite queries are already in the local replica but we don’t have a direct way to access in Motoko yet. Maybe I misunderstand that concept, but I think this would make this kind of access easier…at least on the same subnet.

1 Like

Would it possible to add an optional (likely necessarily synchronous) callback for any declared shared method that would be “reasonably guaranteed to be enqueued/called” (except for in cases when a canister is out of cycles for instance) immediately after that method returns?

Something like the cleanup function that exists for React’s useEffect hook.

1 Like

What would it take to abstract way Iter and have an easier syntax when using for loops?

Being able to write something like this

for (let i = 0; i < 5; i++) {
// Do something
}

Of course, the traditional way using an Iter would still work. It would just be an abstraction, to get a similar feeling to other languages like Python/JavaScript.

Context: I’m asking this because during the Bootcamp I want students to be able to use for loops on their first day without having to introduce a more advanced concept like Iter.

2 Likes

@Seb, C-style for loops are among the most error-prone loop constructs in existence (and discouraged in many modern style guides). Motoko very intentionally does not include them. I don’t think using for (i in range(0, 5)) requires understanding the iterator protocol. For beginners not handicapped by prior Python/JS exposure, I would hope it’s actually easier. :wink:

8 Likes

As a worked example: https://m7sm4-2iaaa-aaaab-qabra-cai.ic0.app

Some of this syntax isn’t intuitive, but I’d think this was pretty simple for a beginner. Honestly, I’d forgotten that range was even in Iter.

Sometimes I wish base was just always there and I could just do base.iter.range or base.buffer or base.nat32.toNat. Maybe the compiler could get smart enough to back fill what is actually used?

Edit: I messed up the paste and the example is lost to history…it was basically


import {range} from "mo:base/Iter";

....and then later....

for(thisItem in range(1,5){
  x += thisItem;
};
2 Likes

would it be possible to add some kind of pipe operator syntax similar to Elixir? eg:

String.split(String.upcase("Elixir rocks"))
"Elixir rocks" |> String.upcase() |> String.split()
["ELIXIR", "ROCKS"]

https://elixirschool.com/en/lessons/basics/pipe_operator

1 Like

Wrote down some thoughts

6 Likes

I’m happy to share that we are getting started on interpolation! The language team also brought up the challenges with stringification, which we also want to tackle, but won’t be in the immediate scope.

5 Likes

Something similar came up in the context of cleaning up side effects (iirc specifically guaranteeing releasing a lock at “the end” of the function), or at least I was reminded by that when reading this article:

Maybe something that could be used to improve Motoko?