Developer Journey: Feedback and discussion

Jessie I noticed in 2.1 that I got the same “already installed” message when you did the upgrade as I did:

dfx canister install counter_backend --mode upgrade
Upgrading code for canister counter_backend, with canister ID bkyz2-fmaaa-aaaaa-qaaaq-cai
Module hash 7020fa1900e17060a542586720a30c0fec19e87670e8a14e0f2891c6a0229e23 is already installed.

Clearly its not a fatal error, but I’m wondering if you could explain what it means. The new code is not installed. So what is already installed? (BTW I did search for this on the forums before posting here and did not find)

Hi @peterkayhi , the code from when you ran the dfx deploy counter_backend command is installed. The dfx deploy command does a few things in the background, such as generate the Candid interface files, compile the canister’s code into a Wasm module, then install that module into the canister.

In the video tutorial, I got this error because I only ran dfx canister install, which didn’t rebuild the Wasm module with the new hash, resulting in that error. But once I ran dfx deploy, since that command includes building the Wasm module as part of the process, you see that the output indicates the canister was upgraded successfully. I could have explained this better in the video, my apologies!

nothing to apologize for! I appreciate you taking the time to reply here.

Hi Jessie - hope my questions are worthy of your time. I’m going through what you’re doing in great detail as I want to completely understand every line of code. I have completed the Motoko Bootcamp so I have some basic familiarity with Motoko and I’m seeing your work as going above and beyond that. I’m really sensitive about wasting people’s time so know that when I’m coming to you it’s because I’ve spent a lot of time to understand every minute detail and exhausted every other avenue (searching, ICP AI, forums etc).

My question centers around understanding 3 lines of code from your 2.2 pub/pub examples (which I copied/pasted from the web page instead of the git versions which have no comments)

Questions on 3 lines of code from 2.2 Advanced canister calls.

Line 16 of pub/main.mo:

callback : shared Counter -> ();  

In the video you said “it’s going to store the result of the shared Counter function” (https://youtu.be/9BfDy3VNxu8?t=1084) but there is no Counter function, right? I can guess this line is related to the intercanister call but I don’t understand exactly how.

Line 31 of pub/main.mo:

subscriber.callback(counter);

This looks like it’s calling a function but there is no such definition. I’m sure it’s related to line 16 but I don’t understand exactly how and what’s going on.

I understand how Sub is importing Pub and using its subscribe function. It’s just those 2 above lines that I cannot fully explain.

Line 22 of sub/main.mo:

callback = updateCount;

I think this one is trivial - it looks like you’re calling updateCount but what’s puzzling is why aren’t you passing a Counter value e.g. updateCount()? how is it you’re able to call updateCount without the ()?

Can you please explain these in detail? I can’t figure out exactly what they are doing and I’ve spent nearly 2 hours and digging through this and articulating my questions (which I hope would have solved it but did not)

@peterkayhi I’m going to defer your questions to @claudio , he may be able to explain the Motoko logic better than I can.

Line 16 is declaring the field ‘callback’ of a record. The field has a shared function type that receives a ‘Counter’ and returns nothing (a one- way or fire-and-forget function that can be called but whose result cannot be awaited).

(In Motoko, functions are first-class values that can be stored in fields, passed as arguments andreturned a results.)

Line 31 access the ‘callback’ field of a ‘subscriber’ record and calls it with an argument.

Line 22 uses the function value ‘updateCount’ as the value of a ‘callback’ field in some larger record.

Hope that helps!

Really appreciate you taking the time to reply - means a lot. Detailed question below and if it’s easier for you to point me to a page that further explains and save you the agony of replying please don’t hesitate.

on the line 22 example (BTW here’s the code and in this version it’s line 17):

it’s making an call to updateCount which is further down (line 21) defined as:

  public func updateCount(counter : Counter) {
    count += counter.value;
  };

my question is why doesn’t

      callback = updateCount;

generate a compile time error? shouldn’t it be

callback = updateCount(someCounterValue);

how is it able to get away with this?

It’s because the type of the callback field is a function type, so it must contain a function value.

  type Subscriber = {
    topic : Text;
    callback : shared Counter -> ();
  };

(examples/motoko/pub-sub/src/pub/Main.mo at 73f624adfca169ed310879bcc88d60963003190f · dfinity/examples · GitHub)

Here, shared Counter -> (); is the type of a (shared) function that takes a Counter value and returns nothing (()).

Note that

  public func updateCount(counter : Counter) {
    count += counter.value;
  };

Is syntactic sugar for

  public shared func updateCount(counter : Counter)   :  () {
    count += counter.value;
  };

(this is because public functions in actors are implicitly shared functions, and omitting the return type is the same as specifying : ())

Given this, updateCount has type shared Counter -> () and can be used as the value of the callback field above.

The reason Motoko gets away with this is that functions are first-class values in Motoko and can be stored in data-structures, variables, fields etc. That’s not a new idea and is present in many modern languages.

(First-class function - Wikipedia)

RESOLVED
Hello,

I am going through the developer journey, and have encountered an issue on 1.5 Deploying Canisters. I have an old identity set up that has an active wallet through dfx wallet, but wanted to follow the tutorial on a fresh identity using the dfx ledger and dfx cycles commands.

My issue:
I’ve sent my own ICP to dfx ledger account-id to add ICP then converted to cycles by command
dfx cycles convert --amount AMOUNT --ic
seen below I call dfx deploy --ic to deploy the poll dapp on 1.5, and get error:
Caused by: No wallet configured for combination of identity 'develop' and network 'ic'

$ dfx deploy --ic 
Please enter the passphrase for your identity: [hidden]
Decryption complete.
Deploying all canisters.
Creating canisters...
Creating canister polling_example_backend...
Error: Failed while trying to deploy canisters.
Caused by: Failed while trying to register all canisters.
Caused by: Failed to create canister 'polling_example_backend'.
Caused by: No wallet configured for combination of identity 'develop' and network 'ic'

In the command below you can see that I have balance, but no wallet configured for ic network.

$ dfx cycles balance --ic
Please enter the passphrase for your identity: [hidden]
Decryption complete.
2.627 TC (trillion cycles).

I ran this command in bash before running the above DFX_CYCLES_LEDGER_SUPPORT_ENABLE=1

Is there a way to use the cycles balance from dfx cycles when using the dfx deploy command?

Sorry if this is somewhere I missed, thanks!

Resolved my issue… was missing export in front of the ledger support command.

I’ve been out for a while and wanted still to thank you for taking the time to explain this to me. It’s much appreciated.

Hello,

I ran into an issue on the example project in 3.4: Introduction to Agents

I get this error when I run dfx generate in the random_maze project

Generating type declarations for canister random_maze_assets:
Error: Failed while trying to generate type declarations for 'random_maze_assets'.
Caused by: Candid file: ../examples/motoko/random_maze/.dfx/local/canisters/random_maze_assets/assetstorage.did doesn't exist.

Afterwards I ran dfx deploy that did not get any errors on the command line, but I do get this in the browser developer console when I press the Generate! button to get the maze
image

I’m using version v16.20.2 of node

Any idea of what could be causing this issue?

Thank you!