Did they mean "." or ":"?

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

Did they mean "." or ":"?

Christopher Eykamp
I'm working on a C++ game that uses Lua scripts to control robot
players.  I'm noticing a common error that the scripters are making, and
am looking for a way to detect it and print a helpful error message.

When the scripters should be writing:

bot:setAngle(angle)

they often write:

bot.setAngle(angle)

which looks similar but is of course very different.  However, anyone
with much experience in Java, C++, etc., is conditioned to see the
second (wrong) version as right, so this is a very difficult bug to
detect while reading the code.

In the setAngle function, I check that the correct number of parameters
is passed, and I generate an error message if that happens.  What I'd
like to do is augment that mechanism by checking if the user used the
"." variant and display a different message that suggests they verify
that they meant to use "." and not ":".

Is there a way from C++ to figure out if a function was called using "."
as opposed to ":"?

Thanks!


Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Geoff Leyland
On 17/02/2010, at 1:05 PM, Christopher Eykamp wrote:

> I'm working on a C++ game that uses Lua scripts to control robot players.  I'm noticing a common error that the scripters are making, and am looking for a way to detect it and print a helpful error message.
>
> When the scripters should be writing:
>
> bot:setAngle(angle)
>
> they often write:
>
> bot.setAngle(angle)
>
> ...
>
> Is there a way from C++ to figure out if a function was called using "." as opposed to ":"?

Is checking the type of the first argument and then writing "Not enough arguments, you probably used '.' instead of ':'" if it's not a bot good enough?

Cheers,
Geoff
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Wesley Smith
In reply to this post by Christopher Eykamp
> Is there a way from C++ to figure out if a function was called using "." as
> opposed to ":"?

What you should be asking instead is how to tell if the object is the
first argument in C++ since bot.setAngle(bot, angle) is equivalent to
bot:setAngle(angle).  If bot is a userdata that you grab the pointer
to, then the check should be trivial.

wes
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Peter Cawley
In reply to this post by Christopher Eykamp
On Wed, Feb 17, 2010 at 12:05 AM, Christopher Eykamp <[hidden email]> wrote:
> Is there a way from C++ to figure out if a function was called using "." as
> opposed to ":"?

In plain Lua, it might be done like:

function how(s, x) return debug.getinfo(1).namewhat == "method" and
":" or "." end
t = {how = how}
print(t.how()) --> .
print(t:how()) --> :

Translating the above into C shouldn't be too hard - just call
lua_getstack() and inspect namewhat. If namewhat is "method" or
"field", then : or . was used respectively. Other values for namewhat
do not help you (for example, if you tailcall t.how() or t:how() then
the call frame is lost, and namewhat will be ""). Note that this is a
debug operation and thus expensive, so only do it once you know the
first parameter is invalid.
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Alex Davies
Peter Cawley wrote:
> In plain Lua, it might be done like:
>
> function how(s, x) return debug.getinfo(1).namewhat == "method" and
> ":" or "." end
> t = {how = how}
> print(t.how()) --> .
> print(t:how()) --> :

Except that then breaks legitimate uses, ie when caching the function lookup
for a tight inner loop.

local setAngle = bot.setAngle
for angle = 0,math.pi,0.0001 do
  setAngle(bot, angle)
end

Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Peter Cawley
On Wed, Feb 17, 2010 at 1:48 AM, Alex Davies <[hidden email]> wrote:

> Peter Cawley wrote:
>> function how(s, x) return debug.getinfo(1).namewhat == "method" and
>> ":" or "." end
>> t = {how = how}
>> print(t.how()) --> .
>> print(t:how()) --> :
>
> Except that then breaks legitimate uses, ie when caching the function lookup
> for a tight inner loop.
>
> local setAngle = bot.setAngle
> for angle = 0,math.pi,0.0001 do
>  setAngle(bot, angle)
> end

In your particular example, namewhat would be "local", rather than
"field" or "method". Whilst you could use my suggestion to force every
call to be via : notation, I intended it to be used *after* you've
realised that your parameters are wrong, to try and tell the user why,
in which case it cannot break any legitimate uses.
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Alex Davies
Peter Cawley wrote:
> In your particular example, namewhat would be "local", rather than
> "field" or "method". Whilst you could use my suggestion to force every
> call to be via : notation, I intended it to be used *after* you've
> realised that your parameters are wrong, to try and tell the user why,
> in which case it cannot break any legitimate uses.

Of course.  Sorry, can't have considered that one correctly.. I was too
eager to look for someone's solution to the problem that'd block legitimate
uses ;).

Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Asko Kauppi
In reply to this post by Christopher Eykamp

A better solution may be to _not_ use the : syntax at all.

I've recently crafted an API for non-programmers, and decided to make  
the whole object system using dot notation. Exactly for the reason of  
not confusing the users on when they need dot, when colon. It's always  
dot.

This is performed by sending the 'this' object as upvalue to all the  
methods. It may give a slight runtime penalty but I doubt it's even  
measurable. Can show you sample if you are interested, but the  
technique has been mentioned on the list before.

-asko


Christopher Eykamp kirjoitti 17.2.2010 kello 2:05:

> I'm working on a C++ game that uses Lua scripts to control robot  
> players.  I'm noticing a common error that the scripters are making,  
> and am looking for a way to detect it and print a helpful error  
> message.
>
> When the scripters should be writing:
>
> bot:setAngle(angle)
>
> they often write:
>
> bot.setAngle(angle)
>
> which looks similar but is of course very different.  However,  
> anyone with much experience in Java, C++, etc., is conditioned to  
> see the second (wrong) version as right, so this is a very difficult  
> bug to detect while reading the code.
>
> In the setAngle function, I check that the correct number of  
> parameters is passed, and I generate an error message if that  
> happens.  What I'd like to do is augment that mechanism by checking  
> if the user used the "." variant and display a different message  
> that suggests they verify that they meant to use "." and not ":".
>
> Is there a way from C++ to figure out if a function was called using  
> "." as opposed to ":"?
>
> Thanks!
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Eike Decker
> This is performed by sending the 'this' object as upvalue to all the
> methods. It may give a slight runtime penalty but I doubt it's even
> measurable. Can show you sample if you are interested, but the technique has
> been mentioned on the list before.

Just a thought on that technique:

This works and has some upsides, but it prevents anyone from reusing
functions and also comes at the cost of having one function per
object. If you have say 10 methods and 1000 objects, you generate
10000 functions. This penalty is actually somewhat measurable in terms
of memory usage and might also cost the GC a bit. Though it might be
allowing even faster calls since upvalues avoids you one or two table
lookups (table[k]=>metatable.__index[k]=>function vs.
table[k]=>function).

But performance is usually not the first issue if it's not a strong
constraint for your environment. Versatility and flexibility is
usually for me a constraint of general importance and I found that
functions that are using upvalues for referencing the self table are a
bit less versatile since they can not be reused (or abused - another
constraint in your environment could be that exactly this is not
wanted ;)). On the upside, it's much more simple to pass mere
functions with their upvalues around and store them, since it's not
required to bind them to their object (e.g:
   local f = obj.f
   f()
vs
   local f = obj.f
   f(obj)
).

So it's more or less: You should actually know what you are doing ;) -
and the : and . semantics that is often not understood by beginners is
actually a hint to them to get a clear head what all this is meaning.
I learned more about the backgrounds on programming when learning Lua
than I learned when using Java, C, Javascript or PHP - simply because
I had to develop an idea what's going on there on the language level.
Actually, I could even transfer my experience much more often from Lua
to other languages than the other way round.

In short: I am unsure if it isn't better to confuse people (and make
them learn something) than trying to do what they might expect (just
to be confused later on).

Greetings,
Eike
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

steve donovan
On Wed, Feb 17, 2010 at 9:29 AM, Eike Decker <[hidden email]> wrote:
> In short: I am unsure if it isn't better to confuse people (and make
> them learn something) than trying to do what they might expect (just
> to be confused later on).

Yes, using a '.' is a crutch that will lead to much puzzlement later
('why is it s:gmatch(); f:read()?') apart from the potential cost of
so many closures.

Having an unambiguous error - that the self parameter is not the
object type - should keep people on the path of truth ;)

steve d.

PS. As a piece of consistent weirdness, in LuaJava both 'static' and
'non-static' methods use ':'  !
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Phoenix Sol
In reply to this post by Christopher Eykamp
On Feb 16, 2010, at 6:05 PM, Christopher Eykamp <[hidden email]>  
wrote:

> When the scripters should be writing:
>
> bot:setAngle(angle)
>
> they often write:
>
> bot.setAngle(angle)

I think the real issue is that your scripters just aren't beaten enough.

Beat them like you mean business, and teach them to associate the  
colon with 'self':

SELF! COLON! (( WHACK! ))

This could possibly be supplemented with some automated electroshock  
feedback, by testing whether the first parameter to your function is  
the desired userdata, and if not then calling the needed routine (with  
an X10 interface for example) to deliver the necessary electric  
current to the poor tester. If said tester is not the responsible  
script author, he should be supplied with the script author's name and  
a large rubber bludgeon to complete the feedback loop.

You should, of course, avoid hiring masochists (which may be  
increasingly challenging).

See the whitepaper for details.


Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Mark Hamburg
This discussion is also a point to bring up the separate namespace for methods/__methods metatable entry etc discussion. It would result in the lookup failing when using "." rather than ":" and one could associate an __index metamethod that checked to see whether the key really referenced a method and generate an appropriate error.

Mark

Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Christopher Eykamp
In reply to this post by Asko Kauppi
On 2/16/2010 7:51 PM, Asko Kauppi wrote:

>
> A better solution may be to _not_ use the : syntax at all.
>
> I've recently crafted an API for non-programmers, and decided to make
> the whole object system using dot notation. Exactly for the reason of
> not confusing the users on when they need dot, when colon. It's always
> dot.
>
> This is performed by sending the 'this' object as upvalue to all the
> methods. It may give a slight runtime penalty but I doubt it's even
> measurable. Can show you sample if you are interested, but the
> technique has been mentioned on the list before.
>
> -asko

Hi Asko,

If you wouldn't mind, I'd like to see a sample.  Your approach may work
better for me than some of the other proposals here because I'm using
Lunar to do my binding, and I do not have direct access to the object
without modifying Lunar, which I'd prefer not to do.

I do have some reservations about teaching programmers bad habits, but
I'm not sure that that's what your system does.  I do see immense appeal
in eliminating a very common and difficult to detect error.

Thanks,

Chris
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Wesley Smith
> If you wouldn't mind, I'd like to see a sample.  Your approach may work
> better for me than some of the other proposals here because I'm using Lunar
> to do my binding, and I do not have direct access to the object without
> modifying Lunar, which I'd prefer not to do.
>

I did something similar to emulate OpenGL calls with Cairo graphics.
Cairo requires an object to draw with whereas in OpenGL the state
machine lives outside of the library.  If you look at line 260 of this
file, you'll see the for loop that transforms instance methods to
static methods:

http://www.mat.ucsb.edu/projects/luaAV/browser/branches/luaav3/extra/modules/cgl/init.lua

wes
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Christopher Eykamp
In reply to this post by Phoenix Sol
I'm intrigued by your techniques...   :-)

On 2/17/2010 7:12 AM, Phoenix Sol wrote:

> On Feb 16, 2010, at 6:05 PM, Christopher Eykamp <[hidden email]> wrote:
>
>> When the scripters should be writing:
>>
>> bot:setAngle(angle)
>>
>> they often write:
>>
>> bot.setAngle(angle)
>
> I think the real issue is that your scripters just aren't beaten enough.
>
> Beat them like you mean business, and teach them to associate the
> colon with 'self':
>
> SELF! COLON! (( WHACK! ))
>
> This could possibly be supplemented with some automated electroshock
> feedback, by testing whether the first parameter to your function is
> the desired userdata, and if not then calling the needed routine (with
> an X10 interface for example) to deliver the necessary electric
> current to the poor tester. If said tester is not the responsible
> script author, he should be supplied with the script author's name and
> a large rubber bludgeon to complete the feedback loop.
>
> You should, of course, avoid hiring masochists (which may be
> increasingly challenging).
>
> See the whitepaper for details.
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Christopher Eykamp
In reply to this post by Wesley Smith
In the example I gave, yes, your test would work.  But
bot:setAngleToOtherBot(bot2) would fail that test.

On 2/16/2010 4:11 PM, Wesley Smith wrote:

>> Is there a way from C++ to figure out if a function was called using "." as
>> opposed to ":"?
>>      
> What you should be asking instead is how to tell if the object is the
> first argument in C++ since bot.setAngle(bot, angle) is equivalent to
> bot:setAngle(angle).  If bot is a userdata that you grab the pointer
> to, then the check should be trivial.
>
> wes
>    
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Philipp Janda
Hi!

Am 18.02.2010 10:48, schrieb Christopher Eykamp:
> In the example I gave, yes, your test would work.  But
> bot:setAngleToOtherBot(bot2) would fail that test.

I used the attached module to log calls to functions and methods in
userdata. You could do something similar to throw meaningful error
messages, but you might want to disable this when you release and/or at
least add some caching...

>
> On 2/16/2010 4:11 PM, Wesley Smith wrote:
>>> Is there a way from C++ to figure out if a function was called using
>>> "." as
>>> opposed to ":"?
>>>      
>> What you should be asking instead is how to tell if the object is the
>> first argument in C++ since bot.setAngle(bot, angle) is equivalent to
>> bot:setAngle(angle).  If bot is a userdata that you grab the pointer
>> to, then the check should be trivial.
>>
>> wes
>>    
>

Philipp


trace.lua (615 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Javier Guerra Giraldez
In reply to this post by Phoenix Sol
On Wed, Feb 17, 2010 at 10:12 AM, Phoenix Sol <[hidden email]> wrote:
> I think the real issue is that your scripters just aren't beaten enough.
>
> Beat them like you mean business, and teach them to associate the colon with
> 'self':
>
> SELF! COLON! (( WHACK! ))

+1

seriously, i think Lua is (by far) easy enough.  conceps are clear and
they (mostly) don't clash.  adding ambiguity or hidden parameters just
because "i don't know when to use ':' and when '.'" doesn't fly
IMNSHO.

--
Javier
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Christopher Eykamp
In reply to this post by Wesley Smith
On 2/17/2010 1:56 PM, Wesley Smith wrote:

>> If you wouldn't mind, I'd like to see a sample.  Your approach may work
>> better for me than some of the other proposals here because I'm using Lunar
>> to do my binding, and I do not have direct access to the object without
>> modifying Lunar, which I'd prefer not to do.
>>
>>      
> I did something similar to emulate OpenGL calls with Cairo graphics.
> Cairo requires an object to draw with whereas in OpenGL the state
> machine lives outside of the library.  If you look at line 260 of this
> file, you'll see the for loop that transforms instance methods to
> static methods:
>
> http://www.mat.ucsb.edu/projects/luaAV/browser/branches/luaav3/extra/modules/cgl/init.lua
>
> wes
>    
Thanks for posting that, wes.  Analyzing what you were doing helped my
understand another poster's comments about shared functions and the
overhead incurred by using this approach.  In some situations it is
probably not a big deal.  In Bitfighter, some objects have 50 or so
methods (and counting), and, in many cases, may be created and deleted
within a single frame, so I could easily see having to create 500 or
more "customized" methods 50 times per second, which might start
incurring some overhead.

In a situation like the one I imagine you have, there is a single object
that needs to be "wrapped", with a limited number of methods.  
Therefore, for you, the overhead is essentially 0.

Chris
Reply | Threaded
Open this post in threaded view
|

Re: Did they mean "." or ":"?

Christopher Eykamp
In reply to this post by Phoenix Sol
I started poking around in the Lua code to see how "." and ":" are
implemented internally, and I am now wondering what the rationale behind
having these two operators is.  Why not have "." do the same thing that
":" does (allowing us to eliminate ":" at some future point)?  I can see
that having two operators allows tiny efficiencies (don't need to create
and dispose of the local variable self), but also adds complexity and
leads to user error until users are fully trained up on how these
operators work.

It seems to me that it would be worth a tiny machine inefficiency to get
rid of a real human inefficiency.  Am I missing something obvious?

Chris

PS I know the language won't change because of this email, but I would
like to understand the issues better.



On 2/17/2010 7:12 AM, Phoenix Sol wrote:

> On Feb 16, 2010, at 6:05 PM, Christopher Eykamp <[hidden email]> wrote:
>
>> When the scripters should be writing:
>>
>> bot:setAngle(angle)
>>
>> they often write:
>>
>> bot.setAngle(angle)
>
> I think the real issue is that your scripters just aren't beaten enough.
>
> Beat them like you mean business, and teach them to associate the
> colon with 'self':
>
> SELF! COLON! (( WHACK! ))
>
> This could possibly be supplemented with some automated electroshock
> feedback, by testing whether the first parameter to your function is
> the desired userdata, and if not then calling the needed routine (with
> an X10 interface for example) to deliver the necessary electric
> current to the poor tester. If said tester is not the responsible
> script author, he should be supplied with the script author's name and
> a large rubber bludgeon to complete the feedback loop.
>
> You should, of course, avoid hiring masochists (which may be
> increasingly challenging).
>
> See the whitepaper for details.
>
>
12