7po3j-syaaa-aaaal-qbqea-cai.icp0.io Open in urlscan Pro
2a0b:21c0:b002:2:5000:edff:fe0d:98de  Public Scan

URL: https://7po3j-syaaa-aaaal-qbqea-cai.icp0.io/advanced-types/type-bounds.html
Submission: On December 19 via api from US — Scanned from GB

Form analysis 1 forms found in the DOM

<form id="searchbar-outer" class="searchbar-outer">
  <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>

Text Content

 1.  The Motoko Programming Language
 2.  
 3.  Part 1
 4.  1. Introduction
     ❱
 5.  1. 1.1. Getting Started
 6.  2. Common Programming Concepts
     ❱
 7.  1.  2.1. Variables
     2.  2.2. Mutability
     3.  2.3. Comments
     4.  2.4. Types
         ❱
     5.  1. 2.4.1. Tuples
         2. 2.4.2. Records
         3. 2.4.3. Variants
         4. 2.4.4. Immutable Arrays
         5. 2.4.5. Mutable Arrays
     6.  2.5. Operators
         ❱
     7.  1. 2.5.1. Numeric operators
         2. 2.5.2. Relational operators
         3. 2.5.3. Assignment operators
         4. 2.5.4. Text concatenation
         5. 2.5.5. Logical expressions
         6. 2.5.6. Bitwise operators
         7. 2.5.7. Operator precedence
     8.  2.6. Pattern Matching
     9.  2.7. Functions
     10. 2.8. Options and Results
     11. 2.9. Control Flow
         ❱
     12. 1. 2.9.1. If Expression
         2. 2.9.2. If Else Expression
         3. 2.9.3. Switch Expression
     13. 2.10. Objects and Classes
         ❱
     14. 1. 2.10.1. Objects
         2. 2.10.2. Classes
     15. 2.11. Modules and Imports
     16. 2.12. Assertions
 8.  3. Internet Computer Programming Concepts
     ❱
 9.  1. 3.1. Actors
        ❱
     2. 1. 3.1.1. From Actor to Canister
        2. 3.1.2. Canister Calls from Clients
     3. 3.2. Principals and Authentication
     4. 3.3. Async Data
        ❱
     5. 1. 3.3.1. Shared Types
        2. 3.3.2. Candid
     6. 3.4. Basic Memory Persistence
        ❱
     7. 1. 3.4.1. Upgrades
        2. 3.4.2. Stable Variables
 10. 
 11. Part 2
 12. 4. Advanced Types
     ❱
 13. 1. 4.1. Generic Types
     2. 4.2. Subtyping
     3. 4.3. Recursive Types
     4. 4.4. Type Bounds
 14. 5. The Base Library
     ❱
 15. 1. 5.1. Primitive Types
        ❱
     2. 1.  5.1.1. Bool
        2.  5.1.2. Nat
        3.  5.1.3. Int
        4.  5.1.4. Float
        5.  5.1.5. Principal
        6.  5.1.6. Text
        7.  5.1.7. Char
        8.  5.1.8. Bounded Number Types
            ❱
        9.  1. 5.1.8.1. Nat8
            2. 5.1.8.2. Nat16
            3. 5.1.8.3. Nat32
            4. 5.1.8.4. Nat64
            5. 5.1.8.5. Int8
            6. 5.1.8.6. Int16
            7. 5.1.8.7. Int32
            8. 5.1.8.8. Int64
        10. 5.1.9. Blob
     3. 5.2. Utility Modules
        ❱
     4. 1. 5.2.1. Iterators
        2. 5.2.2. Hash
        3. 5.2.3. Option
        4. 5.2.4. Result
        5. 5.2.5. Order
        6. 5.2.6. Error
        7. 5.2.7. Debug
     5. 5.3. Data Structures
        ❱
     6. 1. 5.3.1. Array
        2. 5.3.2. List
        3. 5.3.3. Buffer
        4. 5.3.4. HashMap
        5. 5.3.5. RBTree
     7. 5.4. More Data Structures
     8. 5.5. IC APIs
        ❱
     9. 1. 5.5.1. Time
        2. 5.5.2. Timer
        3. 5.5.3. CertifiedData
        4. 5.5.4. Random
        5. 5.5.5. Experimental
 16. 6. Advanced Concepts
     ❱
 17. 1. 6.1. Async Programming
     2. 6.2. Scalability
        ❱
     3. 1. 6.2.1. Actor Classes
        2. 6.2.2. Stable Storage
     4. 6.3. System API's
        ❱
     5. 1. 6.3.1. Message Inspection
        2. 6.3.2. Timers
        3. 6.3.3. Certified Variables
        4. 6.3.4. Pre-upgrade and Post-upgrade
        5. 6.3.5. Cryptographic Randomness
 18. 
 19. Part 3
 20. 7. Project Deployment
     ❱
 21. 1. 7.1. Installing the SDK
     2. 7.2. Local Deployment
     3. 7.3. Canister Status
     4. 7.4. Identities and PEM Files
     5. 7.5. Cycles and ICP
     6. 7.6. Cycles Wallet
     7. 7.7. IC Deployment
 22. 8. Common Internet Computer Canisters
     ❱
 23. 1. 8.1. IC Management Canister
     2. 8.2. ICP Ledger Canister
     3. 8.3. Cycle Minting Canister
 24. 9. Internet Computer Standards
     ❱
 25. 1. 9.1. ICRC1
 26. 10. Tokenized Comments Example
 27. 
 28. APPENDIX
 29. 11. TABLES


 * Light
 * Rust
 * Coal
 * Navy
 * Ayu


THE MOTOKO PROGRAMMING LANGUAGE BOOK





TYPE BOUNDS

When we express a subtype-supertype relationship by writing T <: U, then we say
that T is a subtype by U. We can use this relationship between two types in the
instantiation of generic types in functions.


TYPE BOUNDS IN FUNCTIONS

Consider the following function signature:

func makeNat<T <: Number>(x : T) : Natural


It's a generic function that specifies a type bound Number for its generic type
parameter T. This is expressed as <T <: Number>.

The function takes an argument of generic bounded type T and returns a value of
type Natural. The function is meant to take a general kind of number and process
it into a Nat.

The types Number and Natural are declared like this:

type Natural = {
    #N : Nat;
};

type Integer = {
    #I : Int;
};

type Floating = {
    #F : Float;
};

type Number = Natural or Integer or Floating;


The types Natural, Integer and Floating are just variants with one field and
associated types Nat, Int and Float respectively.

The Number type is a type union of Natural, Integer and Floating. A type union
is constructed using the or keyword. This means that a Number could be either a
Natural, an Integer or a Floating.

We would use these types to implement our function like this:

import Int "mo:base/Int";
import Float "mo:base/Float";

func makeNat<T <: Number>(x : T) : Natural {
    switch (x) {
        case (#N n) {
            #N n;
        };
        case (#I i) {
            #N(Int.abs(i));
        };
        case (#F f) {
            let rounded = Float.nearest(f);
            let integer = Float.toInt(rounded);
            let natural = Int.abs(integer);
            #N natural;
        };
    };
};


After importing the Int and Float modules from the Base Library, we declare our
function and implement a switch expression for the argument x.

In case we find a #N we know we are dealing with a Natural and thus immediately
return the the same variant and associated value that we refer to as n.

In case we find an #I we know we are dealing with an Integer and thus take the
associated value i and apply the abs() function from the Int module to turn the
Int into a Nat. We return a value of type Natural once again.

In case we find a #F we know we are dealing with a Floating. So we take the
associated value f of type Float, round it off and convert it to an Int using
functions from the Float module and convert to a Nat again to return a value of
type Natural once again.

Lets test our function using some assertions:

assert makeNat(#N 0) == #N 0;

assert makeNat(#I(-10)) == #N 10;

assert makeNat(#F(-5.9)) == #N 6;


We use arguments of type Natural, Integer and Floating with associated types
Nat, Int and Float respectively. They all are accepted by our function.

In all three cases, we get back a value of type Natural with an associated value
of type Nat.


THE ANY AND NONE TYPES

All types in Motoko are bounded by a special type, namely the Any type. This
type is the supertype of all types and thus all types are a subtype of the Any
type. We may refer to it as the top type. Any value or expression in Motoko can
be of type Any.

Another special type in Motoko is the None type. This type is the subtype of all
types and thus all types are a supertype of None. We may refer to it as the
bottom type. No value in Motoko can have the None type, but some expressions
can.

> NOTE
> Even though no value has type None, it is still useful for typing expressions
> that don't produce a value, such as infinite loops, early exits via return and
> throw and other constructs that divert control-flow (like Debug.trap : Text ->
> None)

For any type T in Motoko, the following subtype-supertype relationship holds:

None <: T

T <: Any