Share your favourite helper functions

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Share your favourite helper functions

Post by kikito »

I'm pretty sure it's doable if you have access to Lua's debug library. You can get a list of the current locals with their names, so printing the name of a particular one shouldn't be very different.

The debug lib is not guaranteed to be defined in all cases. A function which relies on debug should take this into account - maybe "failing gracefully" (supressing input from debug if it's not present, instead of just raising an error and dying).
When I write def I mean function.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Share your favourite helper functions

Post by Robin »

kikito wrote:I'm pretty sure it's doable if you have access to Lua's debug library.
Oh, yeah, that might yield some results. Something like:

Code: Select all

function getnameof(value)
  local idx = 1
  while true do
    local ln, lv = debug.getlocal(2, idx)
    if ln ~= nil then
      if value == lv then return ln end
    else
      error "no local name for value found"
    end
    idx = 1 + idx
  end
end
Help us help you: attach a .love.
spir
Citizen
Posts: 76
Joined: Wed Oct 17, 2012 1:12 pm

true escaped quoted string?

Post by spir »

I just realised that, apparently, the "%q" string format tag does not truely escaped newlines !!!

Code: Select all

print (string.format("%q", "XXX\tXXX\nXXX"))
--[[ output:
"XXX\9XXX\
XXX"
]]
Why so? It does escape tab properly, so why not newlines? And what's this backslash roaming there anyway? %q adds an '\' but only "graphical" (so to say), a real '\\' char without escaping the newline. (Hum, I'll check the bytes to see what's in there exactly). However, in the meanwhile, here is a func that does the job. Tell me if it's correct (I'm not sure of all what can be a special char in Lua), and if there is a simpler/better/more efficient way to do it. If you add (as I did) the following meta-incantations, then your strings will print out properly escaped (thus, ideal for programmer feedback) as default:

Code: Select all

string.quoted = function (s)
   local esc_s = s:gsub(".", function (c)
         if     c < ' '   then return '\\' .. string.byte(c)
         elseif c == '\"' then return '\\"'
         elseif c == '\\' then return '\\\\'
         else                  return c
         end
      end
   )
   return '"' .. esc_s .. '"'
end

-- quick test
print(string.quoted( " \t \n \" \\ \0 \31 "))

string_mt = getmetatable("")
string_mt.__tostring = string.quoted

-- re quick test
print " \t \n \" \\ \0 \31 "
Denis
... la vita e estrany ...
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: true escaped quoted string?

Post by Robin »

spir wrote:I just realised that, apparently, the "%q" string format tag does not truely escaped newlines !!!
It does, though.

Code: Select all

somestring = "hello\
world"
is just a different way of saying

Code: Select all

somestring = "hello\nworld"
I agree you'll usually will want the latter way, though, so a replacement function makes sense.

Your string.quoted looks good to me, although I don't know how efficient gsub over "." is.

Two things:

Code: Select all

         elseif c == '"' then return '\\"'
You don't need the backslash there, and in other places you don't use it.

More importantly:

Code: Select all

string_mt = getmetatable("")
string_mt.__tostring = string.quoted
I wouldn't do this.

Normally, tostring is the identity function for strings. So tostring(foo) == foo if foo is a string. Those two lines break that.
Help us help you: attach a .love.
User avatar
Nsmurf
Party member
Posts: 191
Joined: Fri Jul 27, 2012 1:58 am
Location: West coast.

Re: Share your favourite helper functions

Post by Nsmurf »

OBEY!!!
My Blog
UE0gbWUgd2l0aCB0aGUgd29yZCAnSE1TRycgYXMgdGhlIHN1YmplY3Q=
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: Share your favourite helper functions

Post by Inny »

That implementation of math.round on https://love2d.org/wiki/Additional_math is incorrect.

Round(-1.5) == -2, as seen here: http://www.wolframalpha.com/input/?i=round%28-1.5%29
Floor(-1.5+0.5) == -1, as seen here: http://www.wolframalpha.com/input/?i=fl ... %2B+0.5%29

So, implementing round(x) as floor(x+0.5) is wrong.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Share your favourite helper functions

Post by Robin »

Inny wrote:So, implementing round(x) as floor(x+0.5) is wrong.
Not necessarily. There are a lot of different rules for tie-breaking, and one is not necessarily "right" or "wrong".
Help us help you: attach a .love.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: Share your favourite helper functions

Post by Inny »

Robin wrote:
Inny wrote:So, implementing round(x) as floor(x+0.5) is wrong.
Not necessarily. There are a lot of different rules for tie-breaking, and one is not necessarily "right" or "wrong".
Egad, I tested a bunch of values in wolfram alpha and it appears that they implement the Half To Even style. I'm not sure what to think about this now.
spir
Citizen
Posts: 76
Joined: Wed Oct 17, 2012 1:12 pm

Re: true escaped quoted string?

Post by spir »

Robin wrote: Your string.quoted looks good to me, although I don't know how efficient gsub over "." is.
Yo, I'll change that (with a gsub mapping special chars, and another for the rest of those < 0x20).
Robin wrote: Two things:

Code: Select all

         elseif c == '"' then return '\\"'
You don't need the backslash there, and in other places you don't use it.
I don't get what you mean here: I'm producing an escaped string (thus backslahes are all escaped in the replacement patterns).
Robin wrote: More importantly:

Code: Select all

string_mt = getmetatable("")
string_mt.__tostring = string.quoted
I wouldn't do this.

Normally, tostring is the identity function for strings. So tostring(foo) == foo if foo is a string. Those two lines break that.
Yo, it's a nice property, but have we the choice. __tostring is launched by a call to tostring, isn't it? So, if I want string to be correct eg in table out put, I must hook tostring. So that eg --provided you have a proper tostring for table notation to your taste--, tostring(t) works fine:

Code: Select all

t = {[true]="true", ['nil']="nil", nltab="\n\t", [1]="1", [9]="9"}
print(t)
--> {true="true", 9="9", 1="1", nltab="\n\t", "nil"="nil"}
--  or
--> {true="true", 9="9", 1="1", nltab="\9\10", "nil"="nil"}
-- but not (!) that:
--[[
{true=true, 9=9, 1=1, nltab=
	, nil=nil}
]]
Grrr!!! What the f*$k? How can you debug? I want to string to show correctly. Far more important than tostring(s) == s (when is this useful, anyway, else theoretically?); and it gives another hugely useful (according ti me) property:

programmer --> notation -----> Lua --> tostring of s -------> notation --> programmer

With notations equal on both sides as far as possible (with funcs, threads, userdata, let's wait for next Xmas).
[/code]
... la vita e estrany ...
spir
Citizen
Posts: 76
Joined: Wed Oct 17, 2012 1:12 pm

Re: Share your favourite helper functions

Post by spir »

Inny wrote:That implementation of math.round on https://love2d.org/wiki/Additional_math is incorrect.

Round(-1.5) == -2, as seen here: http://www.wolframalpha.com/input/?i=round%28-1.5%29
Floor(-1.5+0.5) == -1, as seen here: http://www.wolframalpha.com/input/?i=fl ... %2B+0.5%29

So, implementing round(x) as floor(x+0.5) is wrong.
I think as you (but my math knowledge is limited to faraway school). I use the following:

Code: Select all

math.round0 = function (n)       -- to next int (1.5 --> 2, -1.5 --> -2)
   local i = math.floor(n)
   if n >= 0 then
      if (n - i) < 0.5 then return i else return i + 1 end
   else
      if (n - i) <= 0.5 then return i else return i + 1 end
   end
end
math.round = function (n, p)     -- to given power-of-ten precision
   local factor = 10^p
   local mult = n * factor
   local mult_round0 = math.round0(mult)
   return mult_round0 / factor
end
end
with the following test func showing all case combinations I could think at:

Code: Select all

   note("=== rounding to next int ===")
   local rnd0 = math.round0
   for _,i in ipairs {0.0, 1.0, 1.1, 1.5, 1.9} do
      notef("math.round0(%.1f) : %s", i, rnd0(i)) 
   end
   for _,i in ipairs {-1.0, -1.1, -1.5, -1.9} do
      notef("math.round0(%.1f) : %s", i, rnd0(i)) 
   end
   line()
   
   note("=== rounding to given precision ===")
   local rnd = math.round
   local n = 123.4567890
   for _,p in ipairs {7,3,2,1,0,-1,-2} do
      notef("math.round(%f, %d) : %s", n, p, rnd(n,p)) 
   end
   local n = -123.4567890
   for _,p in ipairs {7,3,2,1,0,-1,-2} do
      notef("math.round(%f, %d) : %s", n, p, rnd(n,p)) 
   end
I this correct? And is there a shorter way to express that?
Also, why does do you think Lua provides us with floor and ceil? I think i never, ever needed one of them (and they are highly dangerous to use, due to those corner cases --and we humans seem to be unable to think right with negative numbers, as shown by this example). I constantly need instead int-part and round.

Denis
... la vita e estrany ...
Post Reply

Who is online

Users browsing this forum: Amazon [Bot] and 15 guests