Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Using ':' in a function without being defined?

So, to break it down:

I want to be able to make a function similar to methods inside objects (for example, gui:TweenSize() or part:Destroy()).

I have asked a question similar to this before, and I was told that you cannot make custom methods. But, I thought it would might work if you made one with a function. I have done some testing, and it worked, the only problem being that you had to set the variable used in the function before hand (see example).

Is there any way I can make the setting of obj autonomous without making another function? Would changing it to function ...:methodName() work?


Example

local obj

function obj:methodName()
	print(obj.Name)
end

obj = game.Workspace.Part
obj:methodName()

Thank you!

~TDP

5 comments

0

Reading your question again, are you referring to object-oriented programming?: http://www.lua.org/pil/16.html

0

If you are saying you want to create a custom method for the a class (e.g. BasePart), you cannot as the classes are abstract and can not be made reference to.

0

What if it's a class like Part which has no abstract members?

0

sigh people don't seem to get it. I want to actually make a custom function which has nothing to do with nay object, except that the object can be used to call. I am making a custom method, but used by parts in a different way.

0

I addressed your question in my editted answer. I guess that's what you wanted.

2 answers

✓ Accepted answer

You can't directly add custom methods and properties to parts, but you could wrap them with another table and use metatables to achieve similar effect.

function hasProp( obj, prop )
    -- Hacky way to check if property exists
    -- It literary tries to cause an error to check for property
    local ok = pcall(function()
        local a = obj[prop]
    end)
    return ok
end

function wrapObject( obj, template )
    local custom = {}
    local mt = {}

    -- Index metamethod fires when you try to access non-existant index
    function mt.__index( self, index )
        -- Check if object has this property/method/child
        if hasProp( obj, index ) then
            return obj[index]
        elseif template and template[index] then
            return template[index]
        else
            return nil
        end
    end

    -- Newindex metamethod will fire when you define a new index
    function mt.__newindex( self, index, value )
        if hasProp( obj, index ) then
            obj[index] = value
        else
            rawset( custom, index, value )
        end
    end

    -- Apply the metatable to the custom object
    setmetatable( custom, mt )
    return custom
end

-- Example usage

local part = wrapObject( game.Workspace.Part )
part.Name = "Test"

function part:RandomColor()
    part.BrickColor = BrickColor.random()
end

part:RandomColor()

I can't test this now, but it should work. Also, this will be slower than directly manipulating with object, so avoid it in performance sensitive loops.

Edit: Regards your question, you could make a template table that you pass to the wrapObject function. I update the script with code that would try to read from template as well, if custom property has not been found.

I just tested it and it works great, as well the template idea. This is what you can do with the template:

-- The wrapObject function

local template = {}

function template:RandomColor()
    -- Since this is a method, you can nicely make use of the self variable
    self.BrickColor = BrickColor.random()
end

for i=1,30 do
	local part = wrapObject( Instance.new( "Part", game.Workspace ), template )
	part.Name = "Test"

	part:RandomColor()
end

3 comments

0

This is the best answer that I think will ever be given to me on this. I was looking for something like this. Thank you! It wasn't really answering my question still, but I'll accept your answer anyway, because of what I said right at the start of the comment.

0

Thank you!

Note: I didn't quite get your question, but I hope my answer clears some things up.

An important thing to note is that doing something like Part:Destroy() is exactly the same as doing Part.Destroy(Part). When you invoke a function with :, you are implicitly saying that you want Part to be the first argument of the Destroy function. Doing : is basically syntactic sugar that also reduces the number of keystrokes required to do the same thing.

To simplify things:

a:f(b)

is exactly the same as:

a.f(a, b)

I suppose we should start with something simple. Let's say you have an object called Animal with a property called Sound, and you want to make it so that whenever you do :Cry(n), it prints out Animal.Sound n number of times.

Here's how Animal would look like:

local Animal = {
	Sound = "Quack"
}

And, if we were naive, we would write Cry to look something like this:

function Animal.Cry(animal, n)
	for i = 1, n do
		print(animal.Sound)
	end
end

And if we want to call Cry, we would do this:

Animal.Cry(Animal, 3)

But we want to call Cry like this instead:

Animal:Cry(3)

To fix this, we would rewrite Cry so that it uses :.

function Animal:Cry(n)
	for i = 1, n do
		print(self.Sound)
	end
end

self is special in Lua in that is references the object that called Cry. That is -- it secretly passed as the first parameter of the Cry function.

Animal:Cry(3)
|_____|
   |
   |
 self refers to this

Note that this isn't "true" object-oriented programming.

True object-oriented programming would look something like this:

local Duck = Animal.new("Quack")
local Dog = Animal.new("Bark")

Duck:Cry(1) -- prints "Quack" once
Dog:Cry(2) -- prints "Bark" twice

-- and something about inheritance

But that is outside the scope of this question. Here's a good reference for Lua OOP: http://www.lua.org/pil/16.html

4 comments

0

I already know this, my question was, can I create my own version of this with a function and a value (with the value being the object you are using as the first paramter), e.g, Value:FuncName(otherParams)

0

Is n not a value that was passed into the function Cry of Animal?

0

I still don't get it. Is Animal:Cry(3) not analogous to Value:FuncName(otherParams)?

0

Aah. I think I know what you mean. You want to write a new method for Part (for example)?

This discussion is preserved as it was. New answers, comments, and votes are closed.