How to resolve the algorithm Constrained genericity step by step in the Phix programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Constrained genericity step by step in the Phix programming language

Table of Contents

Problem Statement

Constrained genericity or bounded quantification means that a parametrized type or function (see parametric polymorphism) can only be instantiated on types fulfilling some conditions, even if those conditions are not used in that function. Say a type is called "eatable" if you can call the function eat on it. Write a generic type FoodBox which contains a collection of objects of a type given as parameter, but can only be instantiated on eatable types. The FoodBox shall not use the function eat in any way (i.e. without the explicit restriction, it could be instantiated on any type). The specification of a type being eatable should be as generic as possible in your language (i.e. the restrictions on the implementation of eatable types should be as minimal as possible). Also explain the restrictions, if any, on the implementation of eatable types, and show at least one example of an eatable type.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Constrained genericity step by step in the Phix programming language

Source code in the phix programming language

include builtins\structs.e as structs

class foodbox
    sequence contents = {}
    procedure add(class food)
        -- (aside: class food is 100% abstract here...
        --     ie: class is *the* root|anything class,
        --         and food is just an arbitrary name)
        integer t = structs:get_field_flags(food,"eat")
        if t!=SF_PROC+SF_PUBLIC then 
            throw("not edible") -- no public method eat...
        end if
        -- you might also want something like this:
--      t = structs:fetch_field(food,"eat")
--      if t=NULL then
--          throw("eat not implemented")
--      end if
        this.contents = append(this.contents,food)
    end procedure
    procedure dine()
        integer l = length(this.contents)
        string s = iff(l=1?"":"s")
        printf(1,"foodbox contains %d item%s\n",{l,s})
        for i=1 to l do
            class food = this.contents[i];
            --food.eat();   -- error...
            -- If you don't define an [abstract] eat() method, or use
            --  "class", you end up having to do something like this:
            integer eat = structs:fetch_field(food,"eat")
            eat(food)
        end for
    end procedure
end class
foodbox lunchbox = new()

class fruit
    string name
    procedure eat()
        printf(1,"mmm... %s\n",{this.name})
    end procedure
end class
fruit banana = new({"banana"})

class clay
    string name = "fletton"
end class
clay brick = new()

lunchbox.add(banana)
try
    lunchbox.add(brick) -- throws exception
catch e
    printf(1,"%s line %d error: %s\n",{e[E_FILE],e[E_LINE],e[E_USER]})
end try
lunchbox.dine()


abstract class edible
    string name
    procedure eat();    -- (virtual)
end class

class foodbox2
    sequence contents = {}
    procedure add(edible food)
        if food.eat=NULL then -- (optional)
            throw("eat() not implemented")
        end if
        this.contents = append(this.contents,food)
    end procedure
    procedure dine()
        integer l = length(this.contents)
        string s = iff(l=1?"":"s")
        printf(1,"foodbox2 contains %d item%s\n",{l,s})
        for i=1 to l do
            -- this.contents[i].eat() -- not supported, sorry!
            -- compiler needs some more type hints, such as:
            edible food = this.contents[i]
            food.eat()
        end for
    end procedure
end class
foodbox2 lunchbox2 = new()

class fruit2 extends edible
    procedure eat()
        printf(1,"mmm... %s\n",{this.name})
    end procedure
end class
fruit2 banana2 = new({"banana"})

class clay2
    string name = "common fletton"
end class
clay2 brick2 = new()

class drink extends edible
    procedure eat()
        printf(1,"slurp... %s\n",{this.name})
    end procedure
end class
drink milkshake = new({"milkshake"})

lunchbox2.add(banana2)
try
    lunchbox2.add(brick2) -- triggers typecheck
catch e
    printf(1,"%s line %d: %s\n",{e[E_FILE],e[E_LINE],e[E_USER]})
end try
lunchbox2.add(milkshake)
lunchbox2.dine()


  

You may also check:How to resolve the algorithm Bernoulli numbers step by step in the Fōrmulæ programming language
You may also check:How to resolve the algorithm Statistics/Basic step by step in the MiniScript programming language
You may also check:How to resolve the algorithm String case step by step in the PL/I programming language
You may also check:How to resolve the algorithm Password generator step by step in the F# programming language
You may also check:How to resolve the algorithm Constrained genericity step by step in the J programming language