Conditional Function Definition

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Conditional Function Definition

Marcello Chiuminatto

Hi everybody

 

Maybe someone can help with this.

 

I have “polymorphism” situation where I want to define a function that depending on a condition will have different signature and behaviors

 

I would like something like this, but unfortunately does not work. Is there any other way to implement this in lua?

 

MyClass = {

}

 

If somecondition == 1 then

MyClass.f = function (self, x)

               return x*2

end

end

 

if somecondition == 2 then

MyClass.f = function (self, x,y)

               return x*y

end

end

 

if somecondition==3 then – this case escapes from polymorphism since have the same signature that f in somecondition == 2, but I need this anyway.

MyClass.f = function (self, x,y)

               return x/1

end

end

 

 

Thanks in advanced

 

Marcello Chiuminatto E.

 

 

 

 

Reply | Threaded
Open this post in threaded view
|

Re: Conditional Function Definition

Sean Conner
It was thus said that the Great Marcello Chiuminatto once stated:

> Hi everybody
>
> Maybe someone can help with this.
>
> I have "polymorphism" situation where I want to define a function that
> depending on a condition will have different signature and behaviors
>
> I would like something like this, but unfortunately does not work. Is
> there any other way to implement this in lua?
>
> MyClass = {
> }
>
> If somecondition == 1 then
>   MyClass.f = function (self, x)
>                return x*2
>   end
> end
>
> if somecondition == 2 then
>   MyClass.f = function (self, x,y)
>                return x*y
>   end
> end
>
> if somecondition == 3 then
>   -- this case escapes from polymorphism since have the same signature
>   -- that f in somecondition == 2, but I need this anyway.
>
>   MyClass.f = function (self, x,y)
>                return x/1
>   end
> end

  What do you mean by "does not work"?  What error are you seeing?  Because
from what I can see, this will work (you can always pass more parameters
than a Lua function expects---said function will just ignore the extra
parameters).  

  -spc


Reply | Threaded
Open this post in threaded view
|

Re: Conditional Function Definition

Dirk Laurie-2
In reply to this post by Marcello Chiuminatto
2017-03-19 1:50 GMT+02:00 Marcello Chiuminatto <[hidden email]>:

> I have “polymorphism” situation where I want to define a function that
> depending on a condition will have different signature and behaviors

Lua has many mechanisms for polymorphism, but none
of them work exactly as in C++, since the type of a Lua
value at runtime can be anything.

Your code does not work because it tests the function condition
at compile time (i.e. only one of the forms of MyClass.f get compiled)
whereas true polymorphism requires that the results depend on
what arguments you pass. In C terms, you are in effect using #ifdef.

Here for example is a function polymorphic on the number of
arguments.

morphs = {math.exp,math.log,math.max}

function poly1(...)
   return morphs[math.min(select('#',...),3)](...)
end

Reply | Threaded
Open this post in threaded view
|

RE: Conditional Function Definition

Marcello Chiuminatto

My approach was wrong, because I was trying to assign the function at loading time (upon require execution) when what I really needed was that the function assignment was in a object by object basis.  This post opened my eyes and finally I found a solution. Thanks, this will save me a lot of lines and ifs when using the module.

 

MyClass.lua

 

MyClass = {

                              myType = "",

                              myCatalog ={type1={}, type2={},type3={},},

                              myVar =0

                                            

function MyClass:new (type)

               o =  {}   -- create object if user does not provide one

               setmetatable(o, self)

               self.__index = self

               o:createCatalog()

               o.f = self.myCatalog[type].f

               return o

end

 

function MyClass:createCatalog()

 

               self.myCatalog["type1"]["f"] = function(self, x)

                                                            return x*2;

               end

 

               self.myCatalog["type2"]["f"] = function(self, x, y)

               return x*y;

               end

 

               self.myCatalog["type3"]["f"] = function(self, x, y)

               return x/y;

               end

end

 

MyClassUser.lua

 

 

require("MyClass")

local obj1 = MyClass:new( "type1");

local obj2 = MyClass:new("type2");

local obj3 = MyClass:new("type3");

 

print (obj1:f(2))

print (obj2:f(2,3))

print (obj3:f(2,3))

 

>lua -e "io.stdout:setvbuf 'no'" "MyClassUser.lua"

4

6

0.66666666666667

 

-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of Dirk Laurie
Sent: Sunday, March 19, 2017 3:20 AM
To: Lua mailing list <[hidden email]>
Subject: Re: Conditional Function Definition

 

2017-03-19 1:50 GMT+02:00 Marcello Chiuminatto <[hidden email]>:

 

> I have “polymorphism” situation where I want to define a function that

> depending on a condition will have different signature and behaviors

 

Lua has many mechanisms for polymorphism, but none of them work exactly as in C++, since the type of a Lua value at runtime can be anything.

 

Your code does not work because it tests the function condition at compile time (i.e. only one of the forms of MyClass.f get compiled) whereas true polymorphism requires that the results depend on what arguments you pass. In C terms, you are in effect using #ifdef.

 

Here for example is a function polymorphic on the number of arguments.

 

morphs = {math.exp,math.log,math.max}

 

function poly1(...)

   return morphs[math.min(select('#',...),3)](...)

end

 

Reply | Threaded
Open this post in threaded view
|

Re: Conditional Function Definition

Parke
On Sun, Mar 19, 2017 at 5:35 AM, Marcello Chiuminatto
<[hidden email]> wrote:
> function MyClass:new (type)
>                o =  {}   -- create object if user does not provide one
>                setmetatable(o, self)
>                self.__index = self
>                o:createCatalog()
>                o.f = self.myCatalog[type].f
>                return o
> end


Hello Marcello,

You probably want "local o = {}".  Otherwise o will be global.
(Welcome to Lua.)

Also, your comment "create object if user does not provide one" is
incorrect.  "o = {}" will always create a new table and assign it to
the global variable o.  There is no way, in your MyClass:new function,
for the user to provide an object.

Also, every time you call MyClass:new, you will call createCatalog.
This means every time you create a new object, you will also create 3
new functions.  For each object after the first object, these three
functions will be redundant.  This is inefficient.

If you have not read Programming in Lua, I recommend it.  Especially
the chapter on metatables:

http://www.lua.org/pil/contents.html#13


-- Here is your code, rewritten to be IMO (minimally?) correct.

MyClass  =  {
  myType     =  "",
  myCatalog  =  {  type1={}, type2={}, type3={},  },
  myVar      =  0 }

MyClass.myCatalog.type1.__index  =  MyClass.myCatalog.type1
MyClass.myCatalog.type2.__index  =  MyClass.myCatalog.type2
MyClass.myCatalog.type3.__index  =  MyClass.myCatalog.type3

function MyClass.myCatalog.type1:f ( x, y )  return x+2  end
function MyClass.myCatalog.type2:f ( x, y )  return x*y  end
function MyClass.myCatalog.type3:f ( x, y )  return x/y  end

function MyClass:new (type)
  local o  =  {}   -- create new object
  setmetatable ( o, self.myCatalog[type] )
  --  o.f  =  self.myCatalog[type].f    -- unnecessary and probably incorrect
  return o
end

local obj1 = MyClass:new("type1");
local obj2 = MyClass:new("type2");
local obj3 = MyClass:new("type3");

print (obj1:f(2))
print (obj2:f(2,3))
print (obj3:f(2,3))


-- Here is how I would rewrite the same code from scratch.

type1, type2, type3  =  {}, {}, {}

type1.__index  =  type1
type2.__index  =  type2
type3.__index  =  type3

function type1 : f (x, y)  return x*2  end
function type2 : f (x, y)  return x*y  end
function type3 : f (x, y)  return x/y  end

local obj1  =  setmetatable ( {}, type1 )
local obj2  =  setmetatable ( {}, type2 )
local obj3  =  setmetatable ( {}, type3 )

print ( obj1 : f ( 2, 3 ) )
print ( obj2 : f ( 2, 3 ) )
print ( obj3 : f ( 2, 3 ) )


Cheers,

Parke

Reply | Threaded
Open this post in threaded view
|

RE: Conditional Function Definition

Marcello Chiuminatto
Thanks Parke!!

You are completely right regarding o and catalog creation, I will fix that and review metatables chapter.

Regards

Marcello Chiuminatto E.


Due to my paradigm I'm trying my code looks

-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of Parke
Sent: Sunday, March 19, 2017 1:52 PM
To: Lua mailing list <[hidden email]>
Subject: Re: Conditional Function Definition

On Sun, Mar 19, 2017 at 5:35 AM, Marcello Chiuminatto <[hidden email]> wrote:
> function MyClass:new (type)
>                o =  {}   -- create object if user does not provide one
>                setmetatable(o, self)
>                self.__index = self
>                o:createCatalog()
>                o.f = self.myCatalog[type].f
>                return o
> end


Hello Marcello,

You probably want "local o = {}".  Otherwise o will be global.
(Welcome to Lua.)

Also, your comment "create object if user does not provide one" is incorrect.  "o = {}" will always create a new table and assign it to the global variable o.  There is no way, in your MyClass:new function, for the user to provide an object.

Also, every time you call MyClass:new, you will call createCatalog.
This means every time you create a new object, you will also create 3 new functions.  For each object after the first object, these three functions will be redundant.  This is inefficient.

If you have not read Programming in Lua, I recommend it.  Especially the chapter on metatables:

http://www.lua.org/pil/contents.html#13


-- Here is your code, rewritten to be IMO (minimally?) correct.

MyClass  =  {
  myType     =  "",
  myCatalog  =  {  type1={}, type2={}, type3={},  },
  myVar      =  0 }

MyClass.myCatalog.type1.__index  =  MyClass.myCatalog.type1 MyClass.myCatalog.type2.__index  =  MyClass.myCatalog.type2 MyClass.myCatalog.type3.__index  =  MyClass.myCatalog.type3

function MyClass.myCatalog.type1:f ( x, y )  return x+2  end function MyClass.myCatalog.type2:f ( x, y )  return x*y  end function MyClass.myCatalog.type3:f ( x, y )  return x/y  end

function MyClass:new (type)
  local o  =  {}   -- create new object
  setmetatable ( o, self.myCatalog[type] )
  --  o.f  =  self.myCatalog[type].f    -- unnecessary and probably incorrect
  return o
end

local obj1 = MyClass:new("type1");
local obj2 = MyClass:new("type2");
local obj3 = MyClass:new("type3");

print (obj1:f(2))
print (obj2:f(2,3))
print (obj3:f(2,3))


-- Here is how I would rewrite the same code from scratch.

type1, type2, type3  =  {}, {}, {}

type1.__index  =  type1
type2.__index  =  type2
type3.__index  =  type3

function type1 : f (x, y)  return x*2  end function type2 : f (x, y)  return x*y  end function type3 : f (x, y)  return x/y  end

local obj1  =  setmetatable ( {}, type1 ) local obj2  =  setmetatable ( {}, type2 ) local obj3  =  setmetatable ( {}, type3 )

print ( obj1 : f ( 2, 3 ) )
print ( obj2 : f ( 2, 3 ) )
print ( obj3 : f ( 2, 3 ) )


Cheers,

Parke