• on implementing a toy oop-system

    From Meredith Montgomery@21:1/5 to All on Sun Sep 4 18:05:31 2022
    Just for investigation sake, I'm trying to simulate OO-inheritance.

    (*) What did I do?

    I decided that objects would be dictionaries and methods would be
    procedures stored in the object. A class is just a procedure that
    creates such object-dictionary. So far so good. Trouble arrived when I decided to have inheritance. The problem might related to the
    lexical-nature of closures, but I'm not sure.

    (*) A problem

    Say I have a Counter-creating object procedure and a Car-creating object procedure. Cars want to track how many times they park, so they inherit
    a counter.

    --8<---------------cut here---------------start------------->8---
    def Car(maker = None, color = None):
    o = inherit(Object(), Counter())
    o["maker"] = maker
    o["color"] = color
    o["speed"] = 0
    --8<---------------cut here---------------end--------------->8---

    What Object() does is just to return a dictionary. What inherit() does
    is just to merge the two dictionaries into a single one (to be used by
    the Car procedure).

    This didn't come out as I expected, though. Let me show you
    step-by-step where the problem is. First, here's a counter in action.

    c1 = Counter()
    c1["inc"]()["inc"]()
    {'id': <function Object.<locals>.id at 0x0000016547C648B0>, 'n': 2, [...]}
    c1["n"]
    2

    That's good and expected: I incremented it twice. But look what happens
    with a Car's counter.

    c = Car()
    c = Car()
    c
    {'id': <function Object.<locals>.id at 0x0000016547C64B80>, 'n': 0,
    'inc': <function Counter.<locals>.inc at 0x0000016547C64C10>, 'dec':
    <function Counter.<locals>.dec at 0x0000016547C64CA0>, 'maker': None,
    'color': None, 'speed': 0, 'accelerate': <function
    Car.<locals>.accelerate at 0x0000016547C64AF0>, 'park': <function
    Car.<locals>.park at 0x0000016547C64D30>}

    c["inc"]()
    {'id': <function Object.<locals>.id at 0x0000016547C64B80>, 'n': 1,
    'inc': <function Counter.<locals>.inc at 0x0000016547C64C10>, 'dec':
    <function Counter.<locals>.dec at 0x0000016547C64CA0>}

    We can see something got incremented! But...

    c["n"]
    0

    Indeed, what got incremented is the dictionary attached to the /inc/
    procedure of the Counter closure, so it's that dictionary that's being
    mutated. My /inherit/ procedure is not able to bring that procedure
    into the Car dictionary.

    Is that at all possible somehow? Alternatively, how would you do your
    toy oop-system?

    (*) Full code below

    from random import random

    def Object():
    myid = random()
    def id():
    return myid
    return {
    "id": id
    }

    def inherit(o, parentObject):
    o.update(parentObject)
    return o

    def Counter(begin_at = 0):
    o = Object()
    o["n"] = begin_at
    def inc():
    nonlocal o
    o["n"] += 1
    return o
    o["inc"] = inc
    def dec():
    nonlocal o
    o["n"] -= 1
    return o
    o["dec"] = dec
    return o

    def Car(maker = None, color = None):
    o = inherit(Object(), Counter())
    o["maker"] = maker
    o["color"] = color
    o["speed"] = 0
    def accelerate(speed):
    nonlocal o
    print(f"Car-{o['id']()}: accelerating to {speed}...")
    o["speed"] = speed
    return o
    o["accelerate"] = accelerate
    def park():
    nonlocal o
    o["speed"] = 0
    o["parked"] = True
    o["inc"]()
    print(f"Car-{o['id']()}: parked! ({o['n']} times)")
    return o
    o["park"] = park
    return o

    def tests():
    c1 = Counter()
    c2 = Counter(100)
    c1["inc"]()["inc"]()
    c2["dec"]()["dec"]()["dec"]()
    print("c1 is 2:", c1["n"])
    print("c2 is 97:", c2["n"])
    car1 = Car("VW", "Red")
    car1["accelerate"](100)
    print("speed is 100:", car1["speed"])
    car2 = Car("Ford", "Black")
    car2["accelerate"](120)["park"]()
    car2["accelerate"](50)["park"]()
    print("has parked 2 times:", car2["n"])

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Meredith Montgomery on Mon Sep 5 08:47:18 2022
    Meredith Montgomery <mmontgomery@levado.to> writes:
    Is that at all possible somehow? Alternatively, how would you do your
    toy oop-system?

    Maybe something along those lines:

    from functools import partial

    def counter_create( object ):
    object[ "n" ]= 0
    def counter_increment( object ):
    object[ "n" ]+= 1
    def counter_value( object ):
    return object[ "n" ]

    counter_class =( counter_create, counter_increment, counter_value )

    def inherit_from( class_, target ):
    class_[ 0 ]( target )
    for method in class_[ 1: ]:
    target[ method.__name__ ]= partial( method, target )

    car = dict()

    inherit_from( counter_class, car )

    print( car[ "counter_value" ]() )
    car[ "counter_increment" ]()
    print( car[ "counter_value" ]() )

    . The "create" part is simplified. I just wanted to show how
    to make methods like "counter_increment" act on the object
    that inherited them using "partial".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Mon Sep 5 11:40:48 2022
    ram@zedat.fu-berlin.de (Stefan Ram) writes:
    Maybe something along those lines:

    A little more elaborated and without "partial":

    # the oop library

    def parent( class_ ):
    parent = None
    try:
    parent = class_[ 'parent' ]
    except KeyError:
    pass
    return parent

    def do_invoke( instance, method, arguments ):
    return method( instance, *arguments )

    def invoke_method_of_class \
    ( instance, selector: str, class_, arguments ):
    assert( type( selector )is str )
    methods = class_[ 'methods' ]
    if selector in methods:
    return do_invoke( instance, methods[ selector ], arguments )
    else:
    par = parent( class_ )
    if par:
    return \
    invoke_method_of_class( instance, selector, par, arguments )

    def invoke_method( instance, selector: str, *arguments ):
    assert( type( selector )is str )
    class_ = instance[ 'class' ]
    return \
    invoke_method_of_class( instance, selector, class_, arguments )

    def prepare_instance( class_, instance ):
    fields = class_[ 'fields' ]
    for field in fields:
    instance[ field ]= fields[ field ]
    methods = class_[ 'methods' ]
    methods[ 'reset' ]( instance )
    par = parent( class_ )
    if par:
    prepare_instance( par, instance )

    def create_instance( class_, instance ):
    instance[ 'class' ]= class_
    prepare_instance( class_, instance )

    def new_instance( class_ ):
    instance = {}
    create_instance( class_, instance )
    return instance

    # class definitions

    def reset( counter ): counter[ 'n' ]= 0
    def greet( counter ): print( "I'm a counter." )
    def increment( counter ): counter[ 'n' ]+= 1
    def value( counter ): return counter[ 'n' ]

    class_counter = \
    { 'name': 'counter',
    'parent': None,
    'methods': \
    { 'reset': reset, # the constructor must be called 'reset'
    'increment': increment, 'value': value, 'greet': greet },
    'fields': { 'n': 0 }}

    def reset( car ): pass
    def greet( car ): print( "I'm a car." )

    class_car = \
    { 'name': 'car',
    'parent': class_counter, # car inherits from counter
    'methods': { 'reset': reset, 'greet': greet },
    'fields': {} }

    # using the classes

    car = new_instance( class_car )
    invoke_method( car, "greet" )
    print( invoke_method( car, "value" ))
    invoke_method( car, "increment" )
    print( invoke_method( car, "value" ))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Meredith Montgomery@21:1/5 to Stefan Ram on Mon Sep 5 14:07:12 2022
    ram@zedat.fu-berlin.de (Stefan Ram) writes:

    Meredith Montgomery <mmontgomery@levado.to> writes:
    Is that at all possible somehow? Alternatively, how would you do your
    toy oop-system?

    Maybe something along those lines:

    from functools import partial

    def counter_create( object ):
    object[ "n" ]= 0
    def counter_increment( object ):
    object[ "n" ]+= 1
    def counter_value( object ):
    return object[ "n" ]

    counter_class =( counter_create, counter_increment, counter_value )

    def inherit_from( class_, target ):
    class_[ 0 ]( target )
    for method in class_[ 1: ]:
    target[ method.__name__ ]= partial( method, target )

    car = dict()

    inherit_from( counter_class, car )

    print( car[ "counter_value" ]() )
    car[ "counter_increment" ]()
    print( car[ "counter_value" ]() )

    . The "create" part is simplified. I just wanted to show how
    to make methods like "counter_increment" act on the object
    that inherited them using "partial".

    That's simple and interesting. I'll study your more elaborate approach
    next, but I like what I see already. Thank you so much.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Meredith Montgomery@21:1/5 to Stefan Ram on Fri Sep 23 17:59:12 2022
    ram@zedat.fu-berlin.de (Stefan Ram) writes:

    Meredith Montgomery <mmontgomery@levado.to> writes:
    Is that at all possible somehow? Alternatively, how would you do your
    toy oop-system?

    Maybe something along those lines:

    from functools import partial

    def counter_create( object ):
    object[ "n" ]= 0
    def counter_increment( object ):
    object[ "n" ]+= 1
    def counter_value( object ):
    return object[ "n" ]

    counter_class =( counter_create, counter_increment, counter_value )

    def inherit_from( class_, target ):
    class_[ 0 ]( target )
    for method in class_[ 1: ]:
    target[ method.__name__ ]= partial( method, target )

    car = dict()

    inherit_from( counter_class, car )

    print( car[ "counter_value" ]() )
    car[ "counter_increment" ]()
    print( car[ "counter_value" ]() )

    . The "create" part is simplified. I just wanted to show how
    to make methods like "counter_increment" act on the object
    that inherited them using "partial".

    I really liked this idea. I organized it my way. Have a look. (Thank
    you for the lecture!)

    --8<---------------cut here---------------start------------->8---
    from functools import partial

    def Counter(name = None):
    o = {"name": name if name else "untitled", "n": 0}
    def inc(o):
    o["n"] += 1
    return o
    o["inc"] = inc
    def get(o):
    return o["n"]
    o["get"] = get
    return o

    def Car(maker):
    o = {"maker": maker, "state": "off"}
    inherit_from(Counter, o)
    def on(o):
    if o["is_on"]():
    raise ValueError("oh, no: car is already on")
    o["inc"]()
    print(f"{o['maker']}: bruum!")
    o["state"] = "on"
    return o
    o["on"] = partial(on, o)
    def off(o):
    if o["is_off"]():
    raise ValueError("oh, no: car is already off")
    print(f"{o['maker']}: spat!")
    o["state"] = "off"
    return o
    o["off"] = partial(off, o)
    def is_on(o):
    return o["state"] == "on"
    o["is_on"] = partial(is_on, o)
    def is_off(o):
    return o["state"] == "off"
    o["is_off"] = partial(is_off, o)
    return o

    def main():
    car1 = Car("Ford")
    car2 = Car("VW")
    for i in range(5):
    car1["on"](); car1["off"]()
    for i in range(3):
    car2["on"](); car2["off"]()
    print(f"car turned on = {car1['get']()} ({car1['maker']})")
    print(f"car turned on = {car2['get']()} ({car2['maker']})")

    ## (*) How to inherit the methods from a class
    ##
    def inherit_from(C, target):
    o = C()
    for k, v in o.items():
    if callable(v):
    target[k] = partial(v, target)
    else:
    target[k] = v
    --8<---------------cut here---------------end--------------->8---

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to mmontgomery@levado.to on Sat Sep 24 08:06:31 2022
    On Sat, 24 Sept 2022 at 07:52, Meredith Montgomery
    <mmontgomery@levado.to> wrote:

    def Counter(name = None):
    o = {"name": name if name else "untitled", "n": 0}
    def inc(o):
    o["n"] += 1
    return o
    o["inc"] = inc
    def get(o):
    return o["n"]
    o["get"] = get
    return o


    Want a neat demo of how classes and closures are practically the same thing?

    def Counter(name=None):
    if not name: name = "untitled"
    n = 0
    def inc():
    nonlocal n; n += 1
    def get():
    return n
    return locals()

    Aside from using a nonlocal declaration rather than "self.n", this is
    extremely similar to classes, yet there are no classes involved.

    A class statement creates a namespace. The locals() function returns
    the function's namespace.

    Each call to Counter() creates a new closure context, just like each
    call to a constructor creates a new object.

    There's very little difference, at a fundamental level :)

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Meredith Montgomery@21:1/5 to Chris Angelico on Fri Sep 23 22:08:16 2022
    Chris Angelico <rosuav@gmail.com> writes:

    On Sat, 24 Sept 2022 at 07:52, Meredith Montgomery
    <mmontgomery@levado.to> wrote:

    def Counter(name = None):
    o = {"name": name if name else "untitled", "n": 0}
    def inc(o):
    o["n"] += 1
    return o
    o["inc"] = inc
    def get(o):
    return o["n"]
    o["get"] = get
    return o


    Want a neat demo of how classes and closures are practically the same thing?

    def Counter(name=None):
    if not name: name = "untitled"
    n = 0
    def inc():
    nonlocal n; n += 1
    def get():
    return n
    return locals()

    Aside from using a nonlocal declaration rather than "self.n", this is extremely similar to classes, yet there are no classes involved.

    A class statement creates a namespace. The locals() function returns
    the function's namespace.

    Each call to Counter() creates a new closure context, just like each
    call to a constructor creates a new object.

    There's very little difference, at a fundamental level :)

    I started out this way, but I had to change direction to implement
    inheritance: the difficulty with closures seems to be lexical scoping,
    which makes it hard (or impossible) for me to move these closures to
    another ``object''. For instance, the nonlocal /n/ in /inc/ above is
    forever bound to that closure; there seems to be no way to make /inc/
    update some /n/ in another ``object'', which is needed in my conception
    of inheritance. I think Python would have to let me duplicate closures. (Thanks for showing me /locals()/.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julio Di Egidio@21:1/5 to Chris Angelico on Sat Sep 24 01:21:51 2022
    On Saturday, 24 September 2022 at 00:07:07 UTC+2, Chris Angelico wrote:
    On Sat, 24 Sept 2022 at 07:52, Meredith Montgomery
    <snip>
    A class statement creates a namespace. The locals() function returns
    the function's namespace.

    Each call to Counter() creates a new closure context, just like each
    call to a constructor creates a new object.

    There's very little difference, at a fundamental level :)

    That's like saying that functional and OO are essentially the
    same, i.e. yet another piece of purely upside down spam.

    "Closure" is someway akin to "encapsulation" just because the
    very basic design principles of *modularity* is find in every
    language and piece of code that is not just pure nonsense and
    spaghetti, but the similarity is only superficial, firstly because encapsulation and closure actually and very fundamentally DO
    NOT work the same way (functional is *lexical*, you entire
    generation of incompetent morons and spammers) plus of
    course OO adds inheritance and polymorphism, and altogether
    you and an entire do not even know what your name is anymore...

    HTH,

    Julio

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Meredith Montgomery on Wed Sep 28 19:02:05 2022
    Meredith Montgomery <mmontgomery@levado.to> writes:
    The code below works, but you can see it's kinda ugly. I wish I could >uncurry a procedure, but I don't think this is possible. (Is it?)

    from functools import partial
    from operator import add
    add5 = partial( add, 5 )
    print( add5( 2 ))
    # might be dependent on implementation details of "functools":
    uncurried = add5.func
    print( uncurried( 14, 7 ))

    However, to evaluate a method call such as "o.m( a, a1, ... )",
    currying does not necessarily have to be used. One can as well
    determine the function to be used for "m" from the type of "o"
    and then call that function with arguments "o", "a", "a1", ...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Meredith Montgomery@21:1/5 to Meredith Montgomery on Wed Sep 28 15:25:50 2022
    Meredith Montgomery <mmontgomery@levado.to> writes:

    ram@zedat.fu-berlin.de (Stefan Ram) writes:

    Meredith Montgomery <mmontgomery@levado.to> writes:
    Is that at all possible somehow? Alternatively, how would you do your >>>toy oop-system?

    Maybe something along those lines:

    from functools import partial

    def counter_create( object ):
    object[ "n" ]= 0
    def counter_increment( object ):
    object[ "n" ]+= 1
    def counter_value( object ):
    return object[ "n" ]

    counter_class =( counter_create, counter_increment, counter_value )

    def inherit_from( class_, target ):
    class_[ 0 ]( target )
    for method in class_[ 1: ]:
    target[ method.__name__ ]= partial( method, target )

    car = dict()

    inherit_from( counter_class, car )

    print( car[ "counter_value" ]() )
    car[ "counter_increment" ]()
    print( car[ "counter_value" ]() )

    . The "create" part is simplified. I just wanted to show how
    to make methods like "counter_increment" act on the object
    that inherited them using "partial".

    I really liked this idea. I organized it my way. Have a look. (Thank
    you for the lecture!)

    But it lacks consistency.

    from functools import partial

    def Counter(name = None):
    o = {"name": name if name else "untitled", "n": 0}
    def inc(o):
    o["n"] += 1
    return o
    o["inc"] = inc
    def get(o):
    return o["n"]
    o["get"] = get
    return o

    This parent class is not defined in the same way as the child class
    below. The class below uses partial to fix the object in the method,
    but the parent one does not. We need consistency.

    But if we curry the parent class's methods (that is, if we apply partial
    on it to fix the object in its first argument), we will curry them a
    second time in inherit_from. That won't work. I can't see an elegant
    solution there, so what I'm going to do is to keep a copy of the
    uncurried original method.

    The code below works, but you can see it's kinda ugly. I wish I could
    uncurry a procedure, but I don't think this is possible. (Is it?)

    # -*- mode: python; python-indent-offset: 2 -*-
    def Counter(name = None):
    self = {"name": name if name else "untitled", "n": 0}
    def inc(self):
    self["n"] += 1
    return self
    self["inc_uncurried"] = inc
    self["inc"] = curry(inc, self)
    def get(self):
    return self["n"]
    self["get_uncurried"] = get
    self["get"] = curry(get, self)
    return self

    def Car(maker):
    self = {"maker": maker, "state": "off"}
    inherit_from(Counter, self)
    def on(self):
    if self["is_on"]():
    raise ValueError("oh, no: car is already on")
    self["inc"]()
    print(f"{self['maker']}: bruum!")
    self["state"] = "on"
    return self
    self["on_uncurried"] = on
    self["on"] = curry(on, self)
    def off(self):
    if self["is_off"]():
    raise ValueError("oh, no: car is already off")
    print(f"{self['maker']}: spat!")
    self["state"] = "off"
    return self
    self["off_uncurried"] = off
    self["off"] = curry(off, self)
    def is_on(self):
    return self["state"] == "on"
    self["is_on_uncurried"] = is_on
    self["is_on"] = curry(is_on, self)
    def is_off(self):
    return self["state"] == "off"
    self["is_off_uncurried"] = is_off
    self["is_off"] = curry(is_off, self)
    return self

    def main():
    car1 = Car("Ford")
    car2 = Car("VW")
    for i in range(5):
    car1["on"](); car1["off"]()
    for i in range(3):
    car2["on"](); car2["off"]()
    print(f"car turned on = {car1['get']()} ({car1['maker']})")
    print(f"car turned on = {car2['get']()} ({car2['maker']})")

    main()
    Ford: bruum!
    Ford: spat!
    Ford: bruum!
    Ford: spat!
    Ford: bruum!
    Ford: spat!
    Ford: bruum!
    Ford: spat!
    Ford: bruum!
    Ford: spat!
    VW: bruum!
    VW: spat!
    VW: bruum!
    VW: spat!
    VW: bruum!
    VW: spat!
    car turned on = 5 (Ford)
    car turned on = 3 (VW)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julio Di Egidio@21:1/5 to Meredith Montgomery on Thu Sep 29 00:28:08 2022
    On Wednesday, 28 September 2022 at 20:26:18 UTC+2, Meredith Montgomery wrote:
    Meredith Montgomery <mmont...@levado.to> writes:
    r...@zedat.fu-berlin.de (Stefan Ram) writes:
    <snip>
    . The "create" part is simplified. I just wanted to show how
    to make methods like "counter_increment" act on the object
    that inherited them using "partial".

    I really liked this idea. I organized it my way. Have a look. (Thank
    you for the lecture!)

    But it lacks consistency.

    It lacks all sense, you trolling piece of shit: indeed of all
    the incompetent pretenders and polluters of ponds, Ram
    who presents himself as a "teacher" is by far the most
    despicable and disgusting, a perfect representative of
    contemporary infamy.

    That said, you bunch of spamming pieces of shit are indeed
    just wasting everybody's breathable air: you wanna build an
    OO system, learn how to define a language and compiler and
    the v-tables for polymorphism and what-not, not that stupid
    pseudo-parroting simulation that is as akin to a real language
    as you with a pair of Nikes are to Michael Jordan.

    Fucking generation of twisted nazi retards : get extinguished
    already...

    *Plonk*

    Julio

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Meredith Montgomery@21:1/5 to Stefan Ram on Thu Sep 29 13:37:15 2022
    ram@zedat.fu-berlin.de (Stefan Ram) writes:

    Meredith Montgomery <mmontgomery@levado.to> writes:
    The code below works, but you can see it's kinda ugly. I wish I could >>uncurry a procedure, but I don't think this is possible. (Is it?)

    from functools import partial
    from operator import add
    add5 = partial( add, 5 )
    print( add5( 2 ))
    # might be dependent on implementation details of "functools":
    uncurried = add5.func
    print( uncurried( 14, 7 ))

    It works on my system here. Thank you so much for your help. (I've
    been learning a lot with you!)

    However, to evaluate a method call such as "o.m( a, a1, ... )",
    currying does not necessarily have to be used. One can as well
    determine the function to be used for "m" from the type of "o"
    and then call that function with arguments "o", "a", "a1", ...

    Was that your last approach? I only glanced at it so far. But I
    remember seeing you describing an object and listing out which methods
    were defined for it and then there was one procedure that would take the
    role of invoking the methods (with the proper arguments).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Meredith Montgomery on Thu Sep 29 16:46:58 2022
    Meredith Montgomery <mmontgomery@levado.to> writes:
    ram@zedat.fu-berlin.de (Stefan Ram) writes:
    Meredith Montgomery <mmontgomery@levado.to> writes:
    The code below works, but you can see it's kinda ugly. I wish I could >>>uncurry a procedure, but I don't think this is possible. (Is it?)
    from functools import partial
    from operator import add
    add5 = partial( add, 5 )
    print( add5( 2 ))
    # might be dependent on implementation details of "functools":
    uncurried = add5.func
    print( uncurried( 14, 7 ))
    It works on my system here. Thank you so much for your help. (I've
    been learning a lot with you!)

    Glad to hear that!

    However, to evaluate a method call such as "o.m( a, a1, ... )",
    currying does not necessarily have to be used. One can as well
    determine the function to be used for "m" from the type of "o"
    and then call that function with arguments "o", "a", "a1", ...
    Was that your last approach?

    Yes, I think so.

    (There are also languages with "multi-methods", where upon
    a function call "m( o, o1, ... )" the decision which function
    to call depends on all the types of all the arguments.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Meredith Montgomery@21:1/5 to Stefan Ram on Thu Sep 29 15:00:00 2022
    ram@zedat.fu-berlin.de (Stefan Ram) writes:

    [...]

    However, to evaluate a method call such as "o.m( a, a1, ... )",
    currying does not necessarily have to be used. One can as well
    determine the function to be used for "m" from the type of "o"
    and then call that function with arguments "o", "a", "a1", ...
    Was that your last approach?

    Yes, I think so.

    (There are also languages with "multi-methods", where upon
    a function call "m( o, o1, ... )" the decision which function
    to call depends on all the types of all the arguments.)

    I think Clojure is one such. I've read Part 1 of ``Clojure in Action''
    by Amit Rathore, 2012, Manning, ISBN 9781935182597. I liked it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)