Re: local 'in' syntax

  • From: Laurent Deniau <Laurent.Deniau@xxxxxxx>
  • To: "luajit@xxxxxxxxxxxxx" <luajit@xxxxxxxxxxxxx>
  • Date: Wed, 4 May 2016 14:05:30 +0000


--
Laurent Deniau                           http://cern.ch/mad
Accelerators Beam Physics        mad@xxxxxxx<mailto:mad@xxxxxxx>
CERN, CH-1211 Geneva 23       Tel: +41 (0) 22 767 4647

On 04 May 2016, at 03:12, Eric Man 
<meric.au@xxxxxxxxx<mailto:meric.au@xxxxxxxxx>> wrote:

Following this thread, gave me the idea on how to implement this feature in 
plain lua as a hack, so one can import like:

        local exp, log, sin, cos, tan within (math, 5)

without having to use incompatible syntax.

https://gist.github.com/meric/1883adb92044b75237bb0b42a63d5ed4

I have not figured out how to phase the "5" out. It's used to figure out how 
many local variables to be assigned.

With numbers, I find it even more dangerous than simple table field 
specification in the RHS. To avoid that, I would go for a solution like below.

Best,
Laurent.

local getlocal, setlocal = debug.getlocal, debug.setlocal

local function from_err(k, msg)
  local info = debug.getinfo(3)
  io.stderr:write(string.format(
    "%s:%s:%d: local variable '%s' %s in import block\n",
    info.source:sub(2),info.name,info.currentline,k,msg))
  os.exit()
end

local function from(t)
  local i, ii = 1
  while true do
    local k, v = getlocal(2, i)
    if k == "import" then ii, i, k = i, v or i+1 end
    if k == nil then break end
    i = i + 1
  end
  assert(ii, "'import' not found")
  while true do
    local k, v = getlocal(2, i)
    if k == nil then break
    elseif v  ~= nil then from_err(k, "initialized")
    elseif t[k] == nil then from_err(k, "not found")
    end
    setlocal(2, i, t[k])
    i = i + 1
  end
  setlocal(2, ii, i)
end

local function test(val)
  local import,
        exp, log from (math)
  local sub from (string)
  local sin, cos, tan from (math)

  assert(exp == math.exp)
  assert(log == math.log)
  assert(sin == math.sin)
  assert(cos == math.cos)
  assert(tan == math.tan)

  return exp(val), tan(val)
end

local import,
      asin, acos, atan from (math)

print(asin(1), atan(1), test(1))



On Wed, May 4, 2016 at 7:34 AM, Demi Obenour 
<demetriobenour@xxxxxxxxx<mailto:demetriobenour@xxxxxxxxx>> wrote:
I like this idea a lot.  It solves a really annoying problem.

On Mon, May 2, 2016 at 11:16 AM, Laurent Deniau 
<Laurent.Deniau@xxxxxxx<mailto:Laurent.Deniau@xxxxxxx>> wrote:

On 02 May 2016, at 16:28, Elias Hogstvedt 
<eliashogstvedt@xxxxxxxxx<mailto:eliashogstvedt@xxxxxxxxx>> wrote:

So you don’t use FFI nor JIT options, nor table.new or other useful features 
part of LuaJIT? You don’t use _ENV in Lua PUC? Does it means that you will 
stay with Lua 5.1 forever? (just to be provocative ;-)

I use these things but if I were to make a public lua module I would probably 
check for the availability of ffi and other things. When you have difference in 
syntax this becomes difficult. This change wouldn't break anything existing and 
I probably wouldn't mind if lua had this syntax really. I just wanted to point 
out the slippery slope (from your previous lambda patch) here.

Which is a good thing IMHO… Globals are error prone, except for very well 
established names.

People choose their own variable names and so you often have to go to the top 
of the file to see what the function originally is. It's very clear what 
table.insert is but it's not immediately clear what tinsert, insert, add, push, 
ti, etc is. It also breaks syntax highlighting if you use that.

Right, that is why I will not implement the ‘as’ of Python...

And I never said that it should be part of the trunk, I provide the patches 
for who might be interested. Most users don’t even compile LuaJIT or Lua, 
they just use the default downloaded version.

And it probably sounds like I think you want these to be part of the trunk. I 
just like discussing. :)

I propose, people dispose…

For example, I will not propose my next patch as it is more related to math 
specific applications and it changes the semantic of Lua for one very special 
case of coercion that I dislike… Since I disagree with this semantic, I will 
change it in my application…

Best,
Laurent.

On Mon, May 2, 2016 at 2:51 PM, Laurent Deniau 
<Laurent.Deniau@xxxxxxx<mailto:Laurent.Deniau@xxxxxxx>> wrote:

On 02 May 2016, at 13:37, Elias Hogstvedt 
<eliashogstvedt@xxxxxxxxx<mailto:eliashogstvedt@xxxxxxxxx>> wrote:

Syntactically backwards compatible.

So you don’t use FFI nor JIT options, nor table.new or other useful features 
part of LuaJIT? You don’t use _ENV in Lua PUC? Does it means that you will stay 
with Lua 5.1 forever? (just to be provocative ;-)

If you're writing a lua module with your syntax it would only work in that 
specific version of lua (as I'm sure you know). I'm interested in the idea of 
moving away from lua syntax but then it should be a clear distinction and it 
shouldn't be called lua anymore. One of the reasons I like lua is because it 
has a very simple syntax that's easy to understand.

This localize thing isn't very on topic here but you've proposed a change in 
syntax to make this problem easier to deal with.

you can see it as a missing feature of Lua, that many other programming 
languages have. For example in Python it is the ‘from' qualifier of an 
‘import'. The fact that modules are tables in Lua makes this feature even more 
generic and useful, e.g. to extract component from tables to enhance 
readability:

local x, y, z in vec
— here are lengthy expressions with x, y, z

instead of

local x, y, z = vec.x, vec,y, vec.z — easy to swap .x and .y by mistake in LHS 
vs. RHS.
— here are lengthy expressions with x, y, z

My main issue with this localize everything mentality is that it makes globals 
useless.

Which is a good thing IMHO… Globals are error prone, except for very well 
established names.

When should we use globals? Would you localize math functions if luajit 
optimized accessing globals in a way that made it just as optimal?

Are you sure that math functions are globals? I would say that math is global, 
but not the functions. And yes I prefer by far

local sin, cos, tan in math

— use sin, cos, … as I would in math code.

I prefer to close (in the CS meaning) as much as possible, so this feature 
enforces also better design in your application.

It seems like a hack or a workaround to me.

I don't know much about jit and compilers but I would've thought if you used 
math.sin in a function it would skip looking up _G and math for the sin 
function and just use it directly unless _G or the math table changes which 
would recompile the function. Is that a naive way of going about it?

In fact, optimisation is one concern, readability is more important for me. For 
example I have actually statement like below to avoid my code looking like Java 
with lengthy.dot.path.down.to.functions:

local gmath   = require 'gmath'
local is_number, is_complex, is_scalar,
      is_matrix, is_cmatrix, is_amatrix,
      is_vector, , is_cvector, , is_avector,
      real, imag, conj, ident, min,
      abs, arg, exp, log, sqrt, proj,
      sin, cos, tan, sinh, cosh, tanh,
      asin, acos, atan, asinh, acosh, atanh,
      unm, mod, pow, tostring =
      gmath.is<http://gmath.is/>_number, gmath.is<http://gmath.is/>_complex, 
gmath.is<http://gmath.is/>_scalar,
      gmath.is<http://gmath.is/>_matrix, gmath.is<http://gmath.is/>_cmatrix, 
gmath.isa_matrix,
      gmath.is<http://gmath.is/>_vector, gmath.is<http://gmath.is/>_cvector, 
gmath.is<http://gmath.is/>_avector,
      gmath.real, gmath.imag, gmath.conj, gmath.ident, gmath.min,
      gmath.abs, gmath.arg, gmath.exp, gmath.log, gmath.sqrt, gmath.proj,
      gmath.sin, gmath.cos, gmath.tan, gmath.sinh, gmath.cosh, gmath.tanh,
      gmath.asin, gmath.acos, gmath.atan, gmath.asinh, gmath.acosh, gmath.atanh,
      gmath.unm, gmath.mod, gmath.pow, gmath.tostring

will be soon converted to:

local is_number, is_complex, is_scalar,
      is_matrix, is_cmatrix, is_amatrix,  is_vector, , is_cvector, , is_avector,
      real, imag, conj, ident, min, abs, arg, exp, log, sqrt, proj,
      sin, cos, tan, sinh, cosh, tanh, asin, acos, atan, asinh, acosh, atanh,
      unm, mod, pow, tostring in require ‘gmath'

The big difference, is if I need to add one more function from the gmath 
module, I don’t need to carefully check the shift in LHS vs. RHS, nor wrap the 
lines on the LHS according the length of the (longer) lines on the RHS...

As I said, I like when a language is minimal like Lua, but in some cases (e.g. 
DSL) expressive power and readability matter. What is important, is that 
syntactic extensions do not affect the semantic of the language which is 
already very complete. Modifying the semantic must be done with care! And I 
never said that it should be part of the trunk, I provide the patches for who 
might be interested. Most users don’t even compile LuaJIT or Lua, they just use 
the default downloaded version.

Best,
Laurent.

On Mon, May 2, 2016 at 12:38 PM, Laurent Deniau 
<Laurent.Deniau@xxxxxxx<mailto:Laurent.Deniau@xxxxxxx>> wrote:

On 01 May 2016, at 12:35, Elias Hogstvedt 
<eliashogstvedt@xxxxxxxxx<mailto:eliashogstvedt@xxxxxxxxx>> wrote:

As you've probably noticed lua users aren't too keen on modifying the Lua 
syntax. I personally like seeing efforts like this because I think it's 
interesting but I would never use it myself. Being compatible with Lua 
syntactically is something I think is important.

LuaJIT is already not compatible with Lua 5.2 and 5.3. so it’s a fake argument 
unless you stick to 5.1 + few extensions.

On the other hand this whole "local sin = math.sin" thing is annoying to both 
read and write.

Not only, now that the patch is supporting expr on the RHS, it also allows to 
simplify your module design, i.e. they can return array of values without any 
loss of clarity on the user side. I have many cases like this where I was 
creating “fake” modules to return single value (i.e. constructors) belonging 
internally to the same module:

local vector   = require “vector"   — returns xmatrix.vector, load matrix first
local cvector = require “cvector" — returns xmatrix.cvector, load matrix first
local matrix   = require “matrix”   — returns xmatrix.matrix
local cmatrix = require “cmatrix” — returns xmatrix.cmatrix, load matrix first

with all the intricacy to load in the right order the requirements (e.g. matrix 
module itself). With local ‘in’ syntax, I just need a single module

local matrix in require “matrix” — ok and simple
local vector, cvector, matrix, cmatrix in require “matrix” — ok and simple, 
same syntax...

So for me, it is not convenient and less error prone, it also affects 
(simplify) the way you organise your module. I would not spend my time to add 
only syntactic sugar, unless it has a deep impact on software design. This is 
the case for the two patches I recently proposed. And I don’t have any other 
need in mind about syntax. Maybe in the coming year I will give a try to 
compile FNEW when there is no upvalue (to allow better optimisation of local 
use of lambda) or extend the sink optimisation to a bit bigger size (e.g. 512 
bytes) and small VLA , but it’s a rather harder thing and I have no idea how to 
do it.

  I don't wanna do it in my own code unless it shows actual performance 
benefits from a user point of view. Especially when I think this can be 
automated through preprocessing. (replace all instances of math.sin with 
math_sin and add local math_sin = math.sin on top of the script)

I'll probably experiment with this now. I haven't tried this local thing that 
much but the times I did I don't remember seeing any performance benefits. 
However looking up something in _G that is nil seems especially slow.


Best,
Laurent.

--
Laurent Deniau                           http://cern.ch/mad
Accelerators Beam Physics        mad@xxxxxxx<mailto:mad@xxxxxxx>
CERN, CH-1211 Geneva 23       Tel: +41 (0) 22 767 
4647<tel:%2B41%20%280%29%2022%20767%204647>


On Sat, Apr 30, 2016 at 8:33 PM, Laurent Deniau 
<Laurent.Deniau@xxxxxxx<mailto:Laurent.Deniau@xxxxxxx>> wrote:
On 30 Apr 2016, at 20:30, Laurent Deniau 
<Laurent.Deniau@xxxxxxx<mailto:Laurent.Deniau@xxxxxxx>> wrote:

Dear All,

I have extended the parser of LuaJIT to support the local ‘in’ table notation 
in Lua. This extension is particularly useful for LuaJIT considering the 
frequent needs to have local copy for performance reason. The patch is very 
minimal and simple and extends the parser with only 13 lines.

The syntax extension allows to write:

local exp, log, sin, cos, tan in math

in place of:

local exp, log, sin, cos, tan in math.exp, math.log, math.sin, math.cos, 
math.tan

I wanted to mean =

local exp, log, sin, cos, tan = math.exp, math.log, math.sin, math.cos, math.tan

and avoid mismatch between variables and fields.

The patch is activated by
XCFLAGS+= -DLUAJIT_LOCAL_INTABLE
in Makefile, and it can be found here:
https://github.com/MethodicalAcceleratorDesign/MAD/blob/master/lib/patches/lj_intable.patch

Best,
Laurent.

--
Laurent Deniau                           http://cern.ch/mad
Accelerators Beam Physics        mad@xxxxxxx<mailto:mad@xxxxxxx>
CERN, CH-1211 Geneva 23       Tel: +41 (0) 22 767 
4647<tel:%2B41%20%280%29%2022%20767%204647>











Other related posts: