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

Tables as custom types?

Started by redstonedude0, 12 April 2014 - 08:24 AM
redstonedude0 #1
Posted 12 April 2014 - 10:24 AM
Hi,

I've looked around to see if there is a way to create custom types in computercraft but there doesn't appear to be however after looking at some code from the peripheral API each peripheral seems to be a table of functions however I need to know how to make a function that references the table, this is my current code that i have gathered from the forums however the forums explain it quite poorly so it might not be correct code:


local version = "V1.0"
function help()
  print("OpenPeripheral Render API "..version.." by Redstonedude")
end
function getNewRender()
  return {setPeripheral = setPeripheralFunction, local peripheral = "peripheral string name goes here, code will change it"}
end
function setPeripheralFuncion(peripheral)
  --code to set peripheral goes here
end
CometWolf #2
Posted 12 April 2014 - 11:17 AM
Sounds to me like your looking for OOP in Lua.
http://www.lua.org/pil/16.html

There's a few different ways to go about this really, my prefered method is using metamethods in the following manner.

local obj
obj = {
  new = function() --used to create new instances of the object
    return setmetatable(
	  {
	    --default obj variables
	  },
	  {
	    __index = function(t,k)
		  return obj[k] or nil --checks the object definition for the specified variable
	    end
	  }
    )
  end,
  objFunc = function(self) --note that im passing the instance of the object to the function itself when i use it later
    self.test = 2
  end
}
return obj

This can then be loaded from a seperate file using loadfile

err,obj = loadfile"obj"
test = obj.new()
test:objFunction() -- the ":" makes this the equivalent of test.objFunction(test)
print(test.test) --prints 2
redstonedude0 #3
Posted 12 April 2014 - 01:40 PM
That all looks like quite complex code, would simply creating a table as the type and then copying it whenever you need to create new instances work? I tried it your way but i think i done it wrong, here's my code:

Attempt 1:

Render = {height = 640, width = 640, peripheral = nil}
.
.
o = {}
setmetatable(o,{__index = Render})
return o

Attempt 2:

local Render = {height = 640, width = 640, peripheral = nil}
.
.
o = {}
setmetatable(o,Render)
Render.__index = Render
return o

NOTE: on the link you gave me it tells me to use self instead of Render in the 2nd attempt however i cannot do this as I need Render to be local as i don't want anyone to be able to do Render.peripheral = "…" and therefore override the default settings for Render by accident
CometWolf #4
Posted 12 April 2014 - 02:33 PM
Essentially what my code does is setup a table of functions for the new type to access. the __index metamethod is what the table uses when you look up a non defined key in the table.

test = setmetatable({},_G.term)
test.setCursorPos(1,1) -- would now be the same as term.setCursorPos(1,1)
test.setCursorPos = "derp" --term.setCursorPos would not be affected, but when you now do test.setCursorPos, you get "derp".
This makes it easy to setup a table with default functions.

Alternatively you could do something like this

new = function()
  local render = {}
  render.func = function()
    render.test = "derp"
  end
  return render
end
render = new()
render.func()
print(render.test) --prints "derp"

on the link you gave me it tells me to use self instead of Render in the 2nd attempt however i cannot do this as I need Render to be local
It dosen't really matter what you call the variable, self or render are just variable pointers. Both of which can be localized however you wish.
redstonedude0 #5
Posted 12 April 2014 - 03:43 PM
on the link you gave me it tells me to use self instead of Render in the 2nd attempt however i cannot do this as I need Render to be local
It dosen't really matter what you call the variable, self or render are just variable pointers. Both of which can be localized however you wish.

I mean it wants the method to be called Render:newRender instead of newRender, and i couldn't do this as programs would need to either access Render (which they can't as it's local) or have an 'instance' of Render, which they can't because they need to access the method to get the first 'instance'. also thank you for the explanation

EDIT: in that case what is wrong with my code

    o = {}
    setmetatable(o,{__index = Render})
    return o

?

NOTE: what happens is the preset variables don't transfer however the other methods i have in my code (Render:setPeripheral and Render:getPEripheral) work fine.
Edited on 12 April 2014 - 01:49 PM
ElvishJerricco #6
Posted 12 April 2014 - 04:04 PM
LuaLua is a nice OOP system. At least I think so ;)/>


@class MyClass:LuaObject
	local privateVar

	function (methodWithParam:a andOtherParam:b )
		print(a,b )
	end
end

local obj = ||MyClass new| init|
|obj methodWithParam:1 andOtherParam:2|
Edited on 12 April 2014 - 02:42 PM
CometWolf #7
Posted 12 April 2014 - 04:15 PM
I mean it wants the method to be called Render:newRender instead of newRender, and i couldn't do this as programs would need to either access Render (which they can't as it's local) or have an 'instance' of Render, which they can't because they need to access the method to get the first 'instance'. also thank you for the explanation
How exactly do you expect people to use your API if they can't access anything in it? :P/>


local Render = {height = 640, width = 640, peripheral = nil}
.
.
o = {}    
setmetatable(o,{__index = Render})     
return o
Provided this is what you're doing, it should work fine. How are you checking the variables?

Also the last 3 lines could just be

return setmetatable({},{__index = Render})
setmetatable returns the table it sets the metatable of, so passing it a blank table directly and returning that works just fine.
redstonedude0 #8
Posted 12 April 2014 - 09:45 PM
How exactly do you expect people to use your API if they can't access anything in it? :P/>

Exact usage:

os.loadAPI("renderAPI")
ren = renderAPI,newRender("openperipheral_glassesbridge_0")
ren.addBox(0,0,10,10,0x00FF00,0.5)


Provided this is what you're doing, it should work fine. How are you checking the variables?
In the shell (with outputs):


lua
Lua>>os.loadAPI("renderAPI")
true
Lua>>a = renderAPI,newRender() --not yet implemeted code to allow peripheral to be passed in the constructor, will add when this works so far
Lua>>a.height
nil
Lua>>a.width
nil
Lua>>a.peripheral
nil
Lua>>a.setPeripheral("test name")
attempt to call nil
CometWolf #9
Posted 13 April 2014 - 10:37 AM
Are you actually using commas, or are those supposed to be dots?

Lua>>a = renderAPI,newRender()
redstonedude0 #10
Posted 13 April 2014 - 07:49 PM
Using dots. Fixed it in the end, IDK what I did maybe i mistyped it one time or something but it works now. Thanks for all the help! I can't believe it took me 2 days to find out how to set meta tables yet i made code to create gradient colors by converting decimal to hexadecimal from scratch within 2 hours…. Also CometWolf you were very helpful so if you want to use my renderAPI when it's done i'd be happy to give you a copy, usage is currently like this, and it works:


os.loadAPI("renderAPI")
a = renderAPI.newRender("openperipheral_glassesbridge_0")
--this must go in a loop
a:render()
--current commands:
a:addBox("box1",0,0,16,16,"00FF00",1.0)
a:transformBox("box1",16,16,16,32,32,"FF0000"0.5)
a:removeBox("box1")
--usage explained
a:addBox(string UID,x,y,width,height,color(as a string),opacity)
a:transformBox(UID,ammount of times render() will be called before final transformation (like FPS.Kinda),newX,newY,newWidth,newHeight,newColor(as a string),newOpacity)