Re: Unpack Operator

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Benoît de Chezelles
Hello, I just subscribed to the mailing list so I'll try my best to
put my reply in context:
I'm replying to this message:
http://lua-users.org/lists/lua-l/2018-01/msg00330.html

Paige DePol wrote:

> > > I was thinking of adding named parameters, as well as optional parameters,
> > > and have been figuring out the best way to implement them. One issue I am
> > > trying to sort out is an efficient way to create a function signature that
> > > can be quickly calculated at runtime when necessary. Another issue is
> > > determining a nice readable syntax for named parameters!
> >
> >  Um, how about:
> > local addr,err = net.address2(host = 'www.google.com', proto = 'www')
>
> Yes, either that or with colons perhaps?
>
> local addr,err = net.address2(host: 'www.google.com', proto: 'www')
>
> [...]
>
> With named parameters the coder should also be able to provide the parameters
> themselves in any order, so the following would be the same:
>
> local addr,err = net.address2(host: 'www.google.com', proto: 'www')
> local addr,err = net.address2(proto: 'www', host: 'www.google.com')
>
> At least, that is my goal...

Huge supporter of named parameters here :) It would be great for Lua instead
of relying on 'options' table, with manual local var mappings, like:

-----
-- What I use to do to have 'named arguments' in Lua
function func(opt)
  opt = opt or {}
  local arg1 = opt.arg1 or "default1"
  local arg2 = opt.arg2 or "default2"
  -- use arg1 & arg2
end

func({arg1 = 1, arg2 = 2})

-----
-- Better!
function func(arg1 = "default1", arg2 = "default2")
  -- use arg1 & arg2
end

func(arg1: 1, arg2: 2)

About the syntax that it could have, and the features of this kind of function
call, I want to show what the language Crystal (a compiled language)
has come up with, which is to me the best method call syntax and flexibility
and readability possible:

https://crystal-lang.org/docs/syntax_and_semantics/default_values_named_arguments_splats_tuples_and_overloading.html

Crystal uses the colon syntax for named arguments, but also allows you to use
positional arguments, varargs for positional arguments, and varargs for named
arguments. You can also use an external/internal argument name as described at
the bottom of the above link.

I don't think the distinction between varargs for positional vs named argument
makes sense in Lua, but maybe the rest could?

---------------------------------------------------
-- Here are some basic examples:

-----
-- Use of mixed positional/named arguments/varargs
function some_func(arg1, arg2, ...)
  -- arg1 is 1
  -- arg2 is 2
  -- ... is something like the table {3, 4, "arg5" = 5}
end

some_func(1, arg2: 2, 3, 4, arg5: 5)


-----
-- External/internal argument name
function increment(value, by amount)
  return value + amount
end

increment(1, by: 3)

-----
-- Default arguments
function add(x, y, z = 2)
  return x + y + z
end

add(y: 2, 1) -- 5

Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Sean Conner
It was thus said that the Great Benoît de Chezelles once stated:

> Hello, I just subscribed to the mailing list so I'll try my best to
> put my reply in context:
> I'm replying to this message:
> http://lua-users.org/lists/lua-l/2018-01/msg00330.html
>
> Paige DePol wrote:
> > > > I was thinking of adding named parameters, as well as optional parameters,
> > > > and have been figuring out the best way to implement them. One issue I am
> > > > trying to sort out is an efficient way to create a function signature that
> > > > can be quickly calculated at runtime when necessary. Another issue is
> > > > determining a nice readable syntax for named parameters!

  Which reminds me, as long as the Lua code hasn't been stripped. Lua 5.3
debug.getlocal() can return the names of the function parameters:

        local function parameters(f)
          local function n(s,v)
            v = v + 1
            local name = debug.getlocal(s,v)
            if name then
              return v,name
            end
          end
       
          return n,f,0
        end

        function print_args(f)
          for i,arg in parameters(f) do
            print(i,arg)
          end
          print()
        end

  So there's that ...

  Anyway ...

> > >  Um, how about:
> > > local addr,err = net.address2(host = 'www.google.com', proto = 'www')
> >
> > Yes, either that or with colons perhaps?
> >
> > local addr,err = net.address2(host: 'www.google.com', proto: 'www')
> >
> > [...]
> >
> > With named parameters the coder should also be able to provide the parameters
> > themselves in any order, so the following would be the same:
> >
> > local addr,err = net.address2(host: 'www.google.com', proto: 'www')
> > local addr,err = net.address2(proto: 'www', host: 'www.google.com')
> >
> > At least, that is my goal...
>
> Huge supporter of named parameters here :) It would be great for Lua instead
> of relying on 'options' table, with manual local var mappings, like:
>
> -----
> -- What I use to do to have 'named arguments' in Lua
> function func(opt)
>   opt = opt or {}
>   local arg1 = opt.arg1 or "default1"
>   local arg2 = opt.arg2 or "default2"
>   -- use arg1 & arg2
> end
>
> func({arg1 = 1, arg2 = 2})

  You can drop the parenthesis in this case:

        func { arg1 = 1 , arg2 = 2 }

> -----
> -- Better!
> function func(arg1 = "default1", arg2 = "default2")
>   -- use arg1 & arg2
> end
>
> func(arg1: 1, arg2: 2)
>
> About the syntax that it could have, and the features of this kind of function
> call, I want to show what the language Crystal (a compiled language)
> has come up with, which is to me the best method call syntax and flexibility
> and readability possible:
>
> https://crystal-lang.org/docs/syntax_and_semantics/default_values_named_arguments_splats_tuples_and_overloading.html
>
> Crystal uses the colon syntax for named arguments, but also allows you to use
> positional arguments, varargs for positional arguments, and varargs for named
> arguments. You can also use an external/internal argument name as described at
> the bottom of the above link.
>
> I don't think the distinction between varargs for positional vs named argument
> makes sense in Lua, but maybe the rest could?

  I don't know.  I read the page, and it seems overly complex to me.  I
would have constructed it like:

        def foo(x,y,z,a = 1 , b = 2 , c = 3)
        end

  Calling foo() would be

        foo(1,2,3,4,5,6)
        foo(x = 1 , y = 2 , z = 3 , a = 4 , b = 5 , c = 6)
        foo(*{1,2,3,4,5,6}) # the "splat" operator I guess
        foo(**{"x",5,"y",6,"z",7}) # assuming I got the "splatsplat" operator right

  Instead of complicating the definition, make it so you can do whatever you
want.  I mean, you could mix things up:

        foo(1,2,3,a = 4 , b = 5 , c = 6)
        foo(*{1,2,3},4,5,6)
        foo(1,2,**{"z",5,"b",7})

  But that's me.

  -spc (Also, I don't care for the ':' assignment thing but I could live
        with it ... )


Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Paige DePol
Sean Conner <[hidden email]> wrote:

> Benoît de Chezelles <[hidden email]> wrote:
>> About the syntax that it could have, and the features of this kind of function
>> call, I want to show what the language Crystal (a compiled language)
>> has come up with, which is to me the best method call syntax and flexibility
>> and readability possible:
>>
>> https://crystal-lang.org/docs/syntax_and_semantics/default_values_named_arguments_splats_tuples_and_overloading.html
>>
>> Crystal uses the colon syntax for named arguments, but also allows you to use
>> positional arguments, varargs for positional arguments, and varargs for named
>> arguments. You can also use an external/internal argument name as described at
>> the bottom of the above link.
>>
>> I don't think the distinction between varargs for positional vs named argument
>> makes sense in Lua, but maybe the rest could?

Thanks for sharing that link. That system of defining both positional and
named parameters, both optional, and both with vargs is quite interesting.

I am developing my own fork of Lua and how these definitions work would fit
very well into that design. Thanks for bringing this to my attention!


> I don't know.  I read the page, and it seems overly complex to me.  I
> would have constructed it like:
>
> def foo(x,y,z,a = 1 , b = 2 , c = 3)
> end
>
> Calling foo() would be

Assuming the definition above:

> foo(1,2,3,4,5,6)
Error, too many fixed arguments.

> foo(x = 1 , y = 2 , z = 3 , a = 4 , b = 5 , c = 6)
Error, no named argument 'x'.

> foo(*{1,2,3,4,5,6}) # the "splat" operator I guess

The splat symbol isn't an operator, it is a variable qualifier. If there is
one preceding splat to the variable name it will be an array containing all
the positional parameters not specifically named. If there are two splat
symbols the variable will be a hash containing undefined named parameters.

If there is only a splat symbol and no name it means no optional positional
or named parameters may be passed with two splats. The splat symbol is only
a qualifier for variables in a function definition.

As an example if we redefine 'foo' as:

foo(x, y, z, *more, a = 1, b = 2, c = 3)

foo(1,2,3,4,5,6)
x=1, y=2, z=3, more=[4,5,6]

foo(a = 2)
error: missing positional arguments

foo(1,2,3, a = 2, z = 4)
error: unknown parameter 'z'


If we redefine foo again as:

foo(*, a = 1, b = 2, c = 3, **more)

Now that there is only a single splat operator NO positional arguments will
be allowed, only named ones. Any not listed named parameters that are passed
will be placed in the 'more' hash.

foo(1,2,3, a=4);
error: positional arguments disallowed.

foo(a=1, b=2, c=3, d=4, e=5, f=6)
a=1, b=2, c=3, more={ d=4, e=5, f=6 }


I guess a function that took absolutely zero params would be 'foo(*,**)'!

In my implementation I would just assume the splat or doublesplat effect was
enabled, that is no optional parameters unless specifically declared.

The nice thing is with my Index data type I sort of get Tuples and NamedTuples
for free, which is really nice for implementing optional parameters.

Thanks again for that link, that really works well for me!

~Paige




Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Benoît de Chezelles
In reply to this post by Sean Conner
Sean Conner <[hidden email]> wrote:

> > -----
> > -- What I use to do to have 'named arguments' in Lua
> > function func(opt)
> >   opt = opt or {}
> >   local arg1 = opt.arg1 or "default1"
> >   local arg2 = opt.arg2 or "default2"
> >   -- use arg1 & arg2
> > end
> >
> > func({arg1 = 1, arg2 = 2})
>
>   You can drop the parenthesis in this case:
>
>         func { arg1 = 1 , arg2 = 2 }

Yeah sure, but to me the bad thing about this is 1/ the intermediate table for
the args, and 2/ the need to manually de-construct the table at the beginning
of the function.

>   I would have constructed it like:
>
> def foo(x,y,z,a = 1 , b = 2 , c = 3)
> end
>
>   Calling foo() would be
>
> foo(1,2,3,4,5,6)
> foo(x = 1 , y = 2 , z = 3 , a = 4 , b = 5 , c = 6)
> foo(*{1,2,3,4,5,6}) # the "splat" operator I guess
> foo(**{"x",5,"y",6,"z",7}) # assuming I got the "splatsplat" operator right
>
>   Instead of complicating the definition, make it so you can do whatever you
> want.  I mean, you could mix things up:
>
> foo(1,2,3,a = 4 , b = 5 , c = 6)
> foo(*{1,2,3},4,5,6)
> foo(1,2,**{"z",5,"b",7})

I'm not sure what you mean, but what you're suggesting is possible in
Crystal, for
example the code:

#-----------------------
def foo(x, y, z, a = 1, b = 2, c = 3)
  puts "#{x}, #{y}, #{z}, #{a}, #{b}, #{c}"
end

foo 1, 2, 3, 4, 5, 6
foo x: 1, y: 2, z: 3, a: 4, b: 5, c: 6
foo *{1, 2, 3, 4, 5, 6}
foo **{x: 5, y: 6, z: 7}

puts "You could mix things up"

foo 1, 2, 3, a: 4, b: 5, c: 6

one_two_three = {1, 2, 3}
foo *one_two_three, 4, 5, 6

foo 1, 2, **{z: 5, b: 7}
#-----------------------

Gives:

#-----------------------
1, 2, 3, 4, 5, 6
1, 2, 3, 4, 5, 6
1, 2, 3, 4, 5, 6
5, 6, 7, 1, 2, 3
You could mix things up
1, 2, 3, 4, 5, 6
1, 2, 3, 4, 5, 6
1, 2, 5, 1, 7, 3
#-----------------------

(live at https://carc.in/#/r/3jwq)

Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Paige DePol
Benoît de Chezelles <[hidden email]> wrote:

> I'm not sure what you mean, but what you're suggesting is possible in
> Crystal, for
> example the code:

So the "splat" qualifier is actually an operator as well? I missed the
line that sort of intimated at this possibility and thought that the
symbol was a variable qualifier for function parameters only.

Additionally, a call argument can have a splat (*) or double splat (**).
A splat expands a Tuple into positional arguments, while a double splat
expands a NamedTuple into named arguments. Multiple argument splats and
double splats are allowed.

So this splat and double splat are essentially unpack operators, which
was the original title and discussion topic of this thread. Nice!


> #-----------------------
> def foo(x, y, z, a = 1, b = 2, c = 3)
>  puts "#{x}, #{y}, #{z}, #{a}, #{b}, #{c}"
> end
>
> foo 1, 2, 3, 4, 5, 6

Okay, my reading of the documentation last night lead me to believe there
should be an error that there was no named argument 'a', so how is 4, 5, 6
being assigned to a, b, c in this example?

Oh wait, it's because in this case a, b, c aren't named parameters they are
just positional ones with default values. I see. My bad. Sigh!

So then that does make sense, sorry Sean, I totally was thinking that a, b,
c were named arguments not positional parameters in these specific examples.
As there is no way to easily determine where positional and named parameters
start and stop that is why they use a solo 'splat' marker.


> foo x: 1, y: 2, z: 3, a: 4, b: 5, c: 6
> foo *{1, 2, 3, 4, 5, 6}
> foo **{x: 5, y: 6, z: 7}

So in Crystal you can create tuples using the same syntax we use
for tables in Lua then? Good to know, guess I should have clicked
on the links for Tuple and NamedTuple! And in these cases the
created tuple is just being created and unpacked... that doesn't
seem the most terribly efficient method for passing arguments.


> puts "You could mix things up"
>
> (live at https://carc.in/#/r/3jwq)

Thanks for the live example, that helped to clarify things. The
previous post of mine would have all made sense were the a, b ,c
arguments named and not positional... I still like the syntax
though having to have a solo splat on all functions without any
positional arguments is a bit of a wart.

Obviously, I missed the importance of the solo splat as a way
to separate the two styles of parameters. Because a, b, c had
default parameters I was thinking they were named parameters.

Again, Sean, sorry... I had just misunderstood the syntax s
your examples were correct and my clarifications were not! :(

~Paige
 
Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Benoît de Chezelles
2018-02-10 10:49 GMT-08:00 Paige DePol <[hidden email]>:
> So this splat and double splat are essentially unpack operators, which
> was the original title and discussion topic of this thread. Nice!
Hehe, maybe we're going somewhere after all with all of this!

Next we'll need to find a way to apply all or part of this to Lua.

>> #-----------------------
>> def foo(x, y, z, a = 1, b = 2, c = 3)
>>  puts "#{x}, #{y}, #{z}, #{a}, #{b}, #{c}"
>> end
>>
>> foo 1, 2, 3, 4, 5, 6
>
> Okay, my reading of the documentation last night lead me to believe there
> should be an error that there was no named argument 'a', so how is 4, 5, 6
> being assigned to a, b, c in this example?
>
> Oh wait, it's because in this case a, b, c aren't named parameters they are
> just positional ones with default values. I see. My bad. Sigh!
>
> So then that does make sense, sorry Sean, I totally was thinking that a, b,
> c were named arguments not positional parameters in these specific examples.
> As there is no way to easily determine where positional and named parameters
> start and stop that is why they use a solo 'splat' marker.

Yes exactly, and also positional arguments can be called as named arguments
too (detailed below).

>> foo x: 1, y: 2, z: 3, a: 4, b: 5, c: 6
>> foo *{1, 2, 3, 4, 5, 6}
>> foo **{x: 5, y: 6, z: 7}
>
> So in Crystal you can create tuples using the same syntax we use
> for tables in Lua then? Good to know, guess I should have clicked
> on the links for Tuple and NamedTuple!
>
> And in these cases the
> created tuple is just being created and unpacked... that doesn't
> seem the most terribly efficient method for passing arguments.

Sure, in this case the use of (named)tuple is completely useless, but
when you have
a (named)tuple coming from outside (the caller, generated from a json
string, ..), it
starts to be useful!

About the efficiency, I'll going a bit out of topic here, and I'm not
sure I'll explain it clearly enough..

Basically in Crystal, Tuple & NamedTuple are a compile-time immutable construct,
allocated on the stack (the real stack, there is no VM or bytecode or
anything), as all
the types are known at compile time, the compiler can pass the correct
values from
the (Named)Tuple, or the default values, or positional/named values
at the correct places on the stack so the method body can find them
and use them.

It's not a dynamic data structure that you create then unpack, they
are just a virtual
concept to powerfully manipulate a set of values on the stack (not
sure it even mean
something..), so there is very little to no overhead to use them to
pass args in Crystal.

Quoting a question from above:
> So the "splat" qualifier is actually an operator as well? I missed the
> line that sort of intimated at this possibility and thought that the
> symbol was a variable qualifier for function parameters only.

It's not really an operator, well, it is but it works only on Tuple
(for *) and NamedTuple (for **).

>
>
>> puts "You could mix things up"
>>
>> (live at https://carc.in/#/r/3jwq)
>
> Thanks for the live example, that helped to clarify things. The
> previous post of mine would have all made sense were the a, b ,c
> arguments named and not positional... I still like the syntax
> though having to have a solo splat on all functions without any
> positional arguments is a bit of a wart.
>
> Obviously, I missed the importance of the solo splat as a way
> to separate the two styles of parameters. Because a, b, c had
> default parameters I was thinking they were named parameters.

The solo splat in Crystal is only used to force the user to call the
next arguments using
named parameter, but all params are always callable with its name:

def foo(x, y, *, z = 3)
end

# these calls will always give x = 1, y = 2, z = 3

# normal positional
foo 1, 2

# named positional
foo x: 1, y: 2

# cannot use non-named z arg
foo 1, 2, 3 # => Error

# use named z arg
foo 1, z: 3, 2

# mixing
foo y: 2, 1, z: 3

> Again, Sean, sorry... I had just misunderstood the syntax s
> your examples were correct and my clarifications were not! :(

I'd say "don't be sorry", reading the documentation of a new language
which have different
paradigms and expect to understand everything is a no-no! It's normal
to be confused here I
think, even though one know another language (Lua) very well :)

Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Paige DePol
Benoît de Chezelles <[hidden email]> wrote:

> 2018-02-10 10:49 GMT-08:00 Paige DePol <[hidden email]>:
>> So this splat and double splat are essentially unpack operators, which
>> was the original title and discussion topic of this thread. Nice!
> Hehe, maybe we're going somewhere after all with all of this!
>
> Next we'll need to find a way to apply all or part of this to Lua.

I have an implementation of something I call the Index data type.

By upgrading the VM Instruction from 32bit to 64bit I was able to give each
register a separate offset value. This value is basically the offset into
the Index data type that must be in the register. Also if the index offset
values are not needed there are various extended opmodes available.

This allows for the creation of structs and object variable encapsulation
with very fast access to Index elements at the vm instruction level.
I have the struct and object system defined, tuples are next on my todo
list after I finish coding the object model.


>> Okay, my reading of the documentation last night lead me to believe there
>> should be an error that there was no named argument 'a', so how is 4, 5, 6
>> being assigned to a, b, c in this example?
>>
>> Oh wait, it's because in this case a, b, c aren't named parameters they are
>> just positional ones with default values. I see. My bad. Sigh!
>>
>> So then that does make sense, sorry Sean, I totally was thinking that a, b,
>> c were named arguments not positional parameters in these specific examples.
>> As there is no way to easily determine where positional and named parameters
>> start and stop that is why they use a solo 'splat' marker.
>
> Yes exactly, and also positional arguments can be called as named arguments
> too (detailed below).

I wonder then really... why even have positional vs named arguments? I really
like how they've laid out how it works, but practical examples of the system
at work makes me think that just named arguments would be nicer overall.


>> So in Crystal you can create tuples using the same syntax we use
>> for tables in Lua then? Good to know, guess I should have clicked
>> on the links for Tuple and NamedTuple!
>>
>> And in these cases the
>> created tuple is just being created and unpacked... that doesn't
>> seem the most terribly efficient method for passing arguments.
>
> Sure, in this case the use of (named)tuple is completely useless, but
> when you have
> a (named)tuple coming from outside (the caller, generated from a json
> string, ..), it
> starts to be useful!
>
> About the efficiency, I'll going a bit out of topic here, and I'm not
> sure I'll explain it clearly enough..
>
> Basically in Crystal, Tuple & NamedTuple are a compile-time immutable construct,
> allocated on the stack (the real stack, there is no VM or bytecode or
> anything), as all
> the types are known at compile time, the compiler can pass the correct
> values from
> the (Named)Tuple, or the default values, or positional/named values
> at the correct places on the stack so the method body can find them
> and use them.

This is pretty much what I do as well for tracking elements of a struct,
or the variables defined for an object. The compiler tracks it all and
then uses the offset values in the vm instruction to access the elements.


> It's not a dynamic data structure that you create then unpack, they
> are just a virtual
> concept to powerfully manipulate a set of values on the stack (not
> sure it even mean
> something..), so there is very little to no overhead to use them to
> pass args in Crystal.

In my system they would be subtypes of the Index, however, I plan to use
memory arenas to manage Index allocation. This way I should be able to
ensure speedy reuse of Index data types as the script runs.


> Quoting a question from above:
>> So the "splat" qualifier is actually an operator as well? I missed the
>> line that sort of intimated at this possibility and thought that the
>> symbol was a variable qualifier for function parameters only.
>
> It's not really an operator, well, it is but it works only on Tuple
> (for *) and NamedTuple (for **).

In Lua, however, it could also be used for unpacking tables, either
as an array with *, or as a hash with **.


>> Thanks for the live example, that helped to clarify things. The
>> previous post of mine would have all made sense were the a, b ,c
>> arguments named and not positional... I still like the syntax
>> though having to have a solo splat on all functions without any
>> positional arguments is a bit of a wart.
>>
>> Obviously, I missed the importance of the solo splat as a way
>> to separate the two styles of parameters. Because a, b, c had
>> default parameters I was thinking they were named parameters.
>
> The solo splat in Crystal is only used to force the user to call the
> next arguments using
> named parameter, but all params are always callable with its name:

Yes, somehow I also seem to have missed that the first time through. I
really should probably not try to comprehend things and post about them
after a long day right before bed. I really missed a couple fundamental
things about this model. I think I just assumed that the two argument
types would be discreet and my brain ran from there!


>> Again, Sean, sorry... I had just misunderstood the syntax s
>> your examples were correct and my clarifications were not! :(
>
> I'd say "don't be sorry", reading the documentation of a new language
> which have different
> paradigms and expect to understand everything is a no-no! It's normal
> to be confused here I
> think, even though one know another language (Lua) very well :)

Well in my defense I was tired. I think I also partially have an idea for
how I'd like to implement named parameters. Crystal has some things that
are similar to my ideas so I skipped over the bits that didn't match what
some of my own ideas were and that lead to confusion and a bit of noise.

I still do thank you for sharing this link, it did give me something to
contemplate... especially once I'd properly comprehended the content! ;)

~Paige


Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Sean Conner
It was thus said that the Great Paige DePol once stated:
>
> I wonder then really... why even have positional vs named arguments? I really
> like how they've laid out how it works, but practical examples of the system
> at work makes me think that just named arguments would be nicer overall.

  That's were I was going with my examples.  Perhaps a more concrete example
will help.  In C, you have structures:

        struct foo
        {
          int x;
          int y;
          int z;
          int a;
          int b;
          int c;
        };

  And you can initialize them.  Default, it follows a position notation,
much like function calls:

        struct foo f1 = { 1 , 2 , 3 , 4 , 5 , 6 };

But in C99, you can designate the fields being initialized, so this now
becomes something like named positions:

        struct foo f2 = { .a = 4 , .b = 5 , .c = 6 , .z = 3 , .y = 2 , .x = 1 };

Furthermore, you can mix the two:

        struct foo f3 = { 1 , 2 , 3 , .c = 6 , .b = 5 , .a = 4 };

I don't see why this can't work for function calls as well.

  -spc

Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Tim Hill


> On Feb 10, 2018, at 2:01 PM, Sean Conner <[hidden email]> wrote:
>
> It was thus said that the Great Paige DePol once stated:
>>
>> I wonder then really... why even have positional vs named arguments? I really
>> like how they've laid out how it works, but practical examples of the system
>> at work makes me think that just named arguments would be nicer overall.
>
>  That's were I was going with my examples.  Perhaps a more concrete example
> will help.  In C, you have structures:
>
> struct foo
> {
>  int x;
>  int y;
>  int z;
>  int a;
>  int b;
>  int c;
> };
>
>  And you can initialize them.  Default, it follows a position notation,
> much like function calls:
>
> struct foo f1 = { 1 , 2 , 3 , 4 , 5 , 6 };
>
> But in C99, you can designate the fields being initialized, so this now
> becomes something like named positions:
>
> struct foo f2 = { .a = 4 , .b = 5 , .c = 6 , .z = 3 , .y = 2 , .x = 1 };
>
> Furthermore, you can mix the two:
>
> struct foo f3 = { 1 , 2 , 3 , .c = 6 , .b = 5 , .a = 4 };
>
> I don't see why this can't work for function calls as well.
>
>  -spc
>

The basic problem with any of these suggestions is that it involves making the compiler aware of the signature of a target function. As currently designed, Lua does not need to know ANYTHING about a target function at compile time; neither the number of arguments nor their type(s). Adding named arguments makes things far more complex. First, the compiler will need to know the signature of the target function. How will it do this for different compilation units? Do we add all the mess of header files, or locating some sort of class file look-aside files? This has all the horrors of Java compilation. Second, even if all that WAS available,which function is being called? Remember that functions in Lua are just VALUES, and the actual function to be called is not known until runtime (the “name" of the function is just a transient variable binding). This means that the binding of named values to arguments would need to be done at runtime, and would, upon examination, be functionally identical to packing the args into a table anyway.

The net result would be a significant reduction in function call performance for everyone, just to avoid the occasional use of braces instead of parentheses when calling a function. I dont think this is a good trade-off at all.

—Tim






Reply | Threaded
Open this post in threaded view
|

Re: Unpack Operator

Francisco Olarte
On Sun, Feb 11, 2018 at 8:09 AM, Tim Hill <[hidden email]> wrote:
> The basic problem with any of these suggestions is that it involves making the compiler aware of the signature of a target function. As currently designed, Lua does not need to know ANYTHING about a target function at compile time; neither the number of arguments nor their type(s). Adding named arguments makes things far more complex. First, the compiler will need to know the signature of the target function. How will it do this for different compilation units? Do we add all the mess of header files, or locating some sort of class file look-aside files? This has all the horrors of Java compilation. Second, even if all that WAS available,which function is being called? Remember that functions in Lua are just VALUES, and the actual function to be called is not known until runtime (the “name" of the function is just a transient variable binding). This means that the binding of named values to arguments would need to be done at runtime, and would, upon examination, be functionally identical to packing the args into a table anyway.

> The net result would be a significant reduction in function call performance for everyone, just to avoid the occasional use of braces instead of parentheses when calling a function. I dont think this is a good trade-off at all.

IIRC Python does all kind of named/default argument thingies without
signatures. Of course, as you pointed below, with a huge performance
penalty ( python feels very slow when I use it ). An in python
functions / methods are values too, no headers / compilation needed.
It does so by packing, unpacking and repacking everywhere.

Francisco Olarte.