This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
xArsonisttx's profile picture

Duplicate Function Name Handling

Started by xArsonisttx, 30 June 2016 - 07:05 PM
xArsonisttx #1
Posted 30 June 2016 - 09:05 PM
I am trying to write a multi-purpose API for dealing with monitors for repeated functions I use a lot in similar ways.

I read the wiki on functions here: http://computercraft.../Function_(type)

From what I understand, It states that functions are seen as variables. This means it would just re-write myFunction() to the latter one if two or more statements exist declaring this function (appears to do this with minor testing, unless I just did something wrong).

I was wondering if there was something I missed that handles a feature like this (similar to constructors in java) if I needed to have multiple functions with the same name that accept different amounts of variables, and could someone link me to or give an example if it exists?

Example of what I am talking about:

-- I want it to choose which of these to run based on the number of variables passed to it.

-- Version 1:
function mWrite(monitor, x, y, text)
  monitor.setCursorPos(x,y)
  monitor.write(text)
end

-- version 2: (only if tcolor variable is present)
function mWrite(mon,x,y,text,tcolor)
  monitor.setCursorPos(x,y)
  monitor.setTextColor(tcolor)
  monitor.write(text)

Instead of having to separate them or preform checks for everything in 1 function like the following setup:

function mWrite(monitor, x, y, text, tcolor)
  setCursorPos(x,y)
  if tcolor then
	monitor.setTextColor(tcolor)
  else
	monitor.setTextColor(colors.white)
  end
  monitor.write(text)
end


Thanks!
~xArsonisttx
Edited on 30 June 2016 - 11:47 PM
Emma #2
Posted 01 July 2016 - 01:58 AM
~snip~

No and there is a good reason why not. You see, in Lua types are not enforced like in java, everything pretty much gets coerced (unless you explicitly do a tostring or tonumber) and the logic is performed. This means that a variable could be nil, in this case how would it know if you're actually passing a nil value or if it just simply wasn't supplied. For example:

function foo(a, b, c)

end

function foo(a, b, c, d)

end

foo(3, "hey", 9)
--In the lua interpreter this basically means (if passed to the second function)
foo(3, "hey", 9, nil)
--And when functions have extra arguments, they either get thrown out or if the function asks for them it is passed like so:
function foo(a, b, c, ...)
  --in this case foo will accept extra arguments if they are supplied as a weird psudeo-table, but unpacked at the same time
end
Sorry, the only way to do this in the current version of lua is, as you said, to perform checks to see if there are extra arguments or not.
Edited on 30 June 2016 - 11:59 PM
Bomb Bloke #3
Posted 01 July 2016 - 04:19 AM
The technique described is called "function overloading", and Lua doesn't support it directly.

And why you'd even want to define multiple functions to do the same job is beyond me. Is not this:

function mWrite(mon,x,y,text,tcolor)
	monitor.setCursorPos(x,y)
	if tcolor then monitor.setTextColor(tcolor) end
	monitor.write(text)
end

… shorter than this?:

function mWrite(monitor, x, y, text)
	monitor.setCursorPos(x,y)
	monitor.write(text)
end

function mWrite(mon,x,y,text,tcolor)
	monitor.setCursorPos(x,y)
	monitor.setTextColor(tcolor)
	monitor.write(text)
end

From what I understand, It states that functions are seen as variables.

Well it pretty much does say that, but it's not exactly true.

When you define a function (or coroutine) and go to assign it to a variable, you're really assigning a pointer to the variable. So:

local a = function() end  -- "a" now holds a pointer to a rather pointless function

local b = a  -- Function is not copied, pointer is; "a" and "b" now point to the same function

Tables also work the same way, and make it rather easier to demonstrate, as their content can be modified after construction:

local a = {}
local b = a
b.hello = "world"
print(a.hello)  --> prints "world"

This means that a variable could be nil, in this case how would it know if you're actually passing a nil value or if it just simply wasn't supplied.

This is actually quite possible, and indeed simple:

local function printNumOfArgs(...)
	print(arg.n)
end

printNumOfArgs(nil, nil, nil)  --> prints 3
xArsonisttx #4
Posted 01 July 2016 - 04:40 PM
No and there is a good reason why not. You see, in Lua types are not enforced like in java, everything pretty much gets coerced (unless you explicitly do a tostring or tonumber) and the logic is performed. This means that a variable could be nil, in this case how would it know if you're actually passing a nil value or if it just simply wasn't supplied. For example:

Sorry, the only way to do this in the current version of lua is, as you said, to perform checks to see if there are extra arguments or not.
Thanks. This is what I was looking for. Now, I know exactly what i need to do. I just don't look forward to doing it, although it does shorten my code by a lot since I don't have to try to idiot-proof it multiple times.

The technique described is called "function overloading", and Lua doesn't support it directly.
I knew it had a name, but I forgot what it was called. In hindsight, I feel like an idiot for not trying to find it with google to include as part of the question. By "Lua doesn't support it directly" I am going to assume there is a way, if I put time and effort into it, that I could find a hack write-around that would work out for my needs, but I don't think it would be worth the effort.

And why you'd even want to define multiple functions to do the same job is beyond me.

It is more efficient and better to do it like you said, however it is not good for someone who only knows a few basic things with Computercraft. The reason why I would want something like this is that I was requested to write a touch-screen information board program for another person to use. However, he wanted to learn how to change things on it to meet his needs should he want something different later on.

He does not do well with loops, functions, and if-statement blocks, so I want to be able to break it down into whole pieces that work. It is mostly so that he is not overwhelmed when I merge everything together and he finds a big block of if-then statements and just say "f*** it!". I did plan on trimming it down to be more efficient in the long run. For now, it is also going to serve as a teaching manual since he doesn't bother reading the Wiki or using questions from this site to find out what he needs.

Thank You to both of you for the information. It has been a big help.
Bomb Bloke #5
Posted 02 July 2016 - 12:35 AM
However, he wanted to learn how to change things on it to meet his needs should he want something different later on.

I'd be surprised if he finds a bunch of if/thens to be more overwhelming than a bunch of excess function blocks.

But in any case, there are many ways to skin a cat, and if you really want to do it then this would probably be the simplest:

local mWriteTable() = {
	[4] = function(monitor, x, y, text)  -- Index functions according to the number of arguments they take.
		monitor.setCursorPos(x,y)
		monitor.write(text)
	end,
	
	[5] = function mWrite(mon,x,y,text,tcolor)
	        monitor.setCursorPos(x,y)
	        monitor.setTextColor(tcolor)
	        monitor.write(text)
	end
}

local function mWrite(...)
	mWriteTable[arg.n](unpack(arg))  -- Get the correct function based on the number of arguments, and run it.
end

Not perfect, as unpack doesn't like it if you include nil values, but you aren't likely to be using those anyways.
H4X0RZ #6
Posted 02 July 2016 - 11:30 AM
A quick Google search would have brought to this thread: http://www.computercraft.info/forums2/index.php?/topic/26606-overloading-functions

I already wrote an "API" which handles (almost) everything for you. And as a little addition, it also enforces the argument types :D/>
Edited on 02 July 2016 - 09:30 AM
theoriginalbit #7
Posted 03 July 2016 - 12:29 PM
And why you'd even want to define multiple functions to do the same job is beyond me.
Same job isn't the common use of function overloading. While functional decomposition has us make functions for nice reusable instructions, function overloading is more to allow different kinds of variables to be supplied.

The easiest example would be with Java, just to show the types

public class Vector3D {
  public float x, y, z;

  public void add(Vector3D other) {
    add(other.x, other.y, other.z);
  }

  public void add(float nx, float ny, float nz) {
    x += nx;
    y += ny;
    z += nz;
  }
}

In both of the cases above, the result of either would be addition so the name "add" makes sense. However they handle the parameters passed into them differently.
Bomb Bloke #8
Posted 03 July 2016 - 05:14 PM
There's nothing stopping us from doing that within a single Lua function, either. Java's methods simply force us to repeat ourselves… and it gets worse when we want to handle ints, floats, doubles, etc… :wacko:/>
H4X0RZ #9
Posted 03 July 2016 - 09:51 PM
And why you'd even want to define multiple functions to do the same job is beyond me.
Same job isn't the common use of function overloading. While functional decomposition has us make functions for nice reusable instructions, function overloading is more to allow different kinds of variables to be supplied.

The easiest example would be with Java, just to show the types

public class Vector3D {
  public float x, y, z;

  public void add(Vector3D other) {
	add(other.x, other.y, other.z);
  }

  public void add(float nx, float ny, float nz) {
	x += nx;
	y += ny;
	z += nz;
  }
}

In both of the cases above, the result of either would be addition so the name "add" makes sense. However they handle the parameters passed into them differently.

That's exactly what my "API" does