require() parse error in 5.3.4/5.4.0-work2?

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

require() parse error in 5.3.4/5.4.0-work2?

Kenneth Lorber
require() seems to silently accept extra arguments.  Is this a bug?

Thanks,
Keni


% cat ktest1.lua
print("in ktest1.lua")
% ./lua
Lua 5.4.0  Copyright (C) 1994-2018 Lua.org, PUC-Rio
> require("ktest1","is this an error?")
in ktest1.lua
true


Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Andrew Gierth
>>>>> "Kenneth" == Kenneth Lorber <[hidden email]> writes:

 Kenneth> require() seems to silently accept extra arguments. Is this a
 Kenneth> bug?

Pretty much every function accepts and silently ignores extra arguments,
unless the function itself bothers to check for them and throw an
explicit error.

--
Andrew.

Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Kenneth Lorber


> On Jun 23, 2018, at 8:57 AM, Andrew Gierth <[hidden email]> wrote:
>
>>>>>> "Kenneth" == Kenneth Lorber <[hidden email]> writes:
>
> Kenneth> require() seems to silently accept extra arguments. Is this a
> Kenneth> bug?
>
> Pretty much every function accepts and silently ignores extra arguments,
> unless the function itself bothers to check for them and throw an
> explicit error.
>
> --
> Andrew.

Thanks, and after a little source diving you are correct, but that's not quite the reply I was looking for.

Is there some reason this is a language feature?  Some use-case I don't see?  (If so, why is there the occasional check for extra arguments?)

Is it documented somewhere I missed?

Is there any reason not to add checks for extra arguments?  If it's performance, it could be available as a compile time option.

I'm working for an implementation for 5.3.4.  If there's any interest please let me know or I'll just quietly add it to my copy and stop bothering the list about it.

Thanks,
Keni
Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Francisco Olarte
On Tue, Jun 26, 2018 at 1:13 PM, Kenneth Lorber <[hidden email]> wrote:

> Is there some reason this is a language feature?  Some use-case I don't see?  (If so, why is there the occasional check for extra arguments?)

There are reasons for not checking arguments by default in lua-like
languages, it makes some things easier. From the top of my head, I'm
presently using a single empty function as a default value for
callbacks in one of my systems ( so I just call them ). It is not
really neccessary, but it makes some things like that easier ( and may
be faster, but that is not the point ).


> Is it documented somewhere I missed?

In 3.4.11, more or less, with some examples.

Also, note checking for them in lua is difficult ( i.e., in f(a,b) is
not easy to differentiate a call as f(1,nil)  from f(1) , or f(1,2,
nil) from f(1,2) ( I only know how to do it for the first case if I
just declare f(...) or f(a,b,...) for the second and check
table.unpack(...).n, but I'm not a guru, I only know how to do it in
C, but there all functions work like (...) )

In my code I normally just check where it makes sense (to me) and have
something nicer to do than not checking. Can think of an example now
and may be I haven,t got one in lua ( although the same problem
surfaces in Perl and I know I've done it there ).

> Is there any reason not to add checks for extra arguments?  If it's performance, it could be available as a compile time option.

Besides superb speed, absent code is bug free, maintenance free and
size-optimized ( and this goes for the compile time option too,
remember lua can load() )

Francisco Oalrte.

Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Andrew Gierth
>>>>> "Francisco" == Francisco Olarte <[hidden email]> writes:

 Francisco> Also, note checking for them in lua is difficult ( i.e., in
 Francisco> f(a,b) is not easy to differentiate a call as f(1,nil) from
 Francisco> f(1) , or f(1,2, nil) from f(1,2) ( I only know how to do it
 Francisco> for the first case if I just declare f(...) or f(a,b,...)
 Francisco> for the second and check table.unpack(...).n,

select('#', ...)  is the official way to get the number of items in ...
if you don't otherwise need to table.pack it. (It's kind of irritating
that this takes a function call to do.)

--
Andrew.

Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Thijs Schreijer
In reply to this post by Kenneth Lorber


On 26 Jun 2018, at 13:13, Kenneth Lorber <[hidden email]> wrote:



On Jun 23, 2018, at 8:57 AM, Andrew Gierth <[hidden email]> wrote:

"Kenneth" == Kenneth Lorber <[hidden email]> writes:

Kenneth> require() seems to silently accept extra arguments. Is this a
Kenneth> bug?

Pretty much every function accepts and silently ignores extra arguments,
unless the function itself bothers to check for them and throw an
explicit error.

--
Andrew.

Thanks, and after a little source diving you are correct, but that's not quite the reply I was looking for.

Is there some reason this is a language feature?  Some use-case I don't see?  (If so, why is there the occasional check for extra arguments?)

Is it documented somewhere I missed?

Is there any reason not to add checks for extra arguments?  If it's performance, it could be available as a compile time option.

I'm working for an implementation for 5.3.4.  If there's any interest please let me know or I'll just quietly add it to my copy and stop bothering the list about it.

Thanks,
Keni

To me it is about flexibility, multiple return values, and the ability to only take what is needed. Eg:

   take_two(return_three())

Without a bunch of locals. Why would you even want to limit that and make it an error? It takes flexibility away.

For example: take OpenResty, it uses a lot of those extra checks and it's a pita. See this code for example:


The last argument “socket options” must be a table, not even `nil` is accepted. Hence in the calling code it requires an if-then construct.

So be careful what you wish for with those checks.

Thijs
Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Kenneth Lorber
In reply to this post by Kenneth Lorber
> On 26 Jun 2018, at 13:13, Kenneth Lorber <[hidden email]<mailto:[hidden email]>> wrote:
>
> On Jun 23, 2018, at 8:57 AM, Andrew Gierth <[hidden email]<mailto:[hidden email]>> wrote:
>
> [...]
> To me it is about flexibility, multiple return values, and the ability to only take what is needed. Eg:
>
>    take_two(return_three())
>
> Without a bunch of locals. Why would you even want to limit that and make it an error? It takes flexibility away.
>
> For example: take OpenResty, it uses a lot of those extra checks and it's a pita. See this code for example:
>
> https://github.com/Kong/kong/blob/82a51c4b519728eed4f957fdaa547ed4abea9332/kong/globalpatches.lua#L296-L302
>
> The last argument “socket options” must be a table, not even `nil` is accepted. Hence in the calling code it requires an if-then construct.
>
> So be careful what you wish for with those checks.
>
> Thijs

I was going to just let this go, but the replies are getting so far afield I just can't.  I'm not asking about the language feature in general, or about function prototypes, or  user written code or any of the other things people have brought up.

I'm talking about the basic, lua-distribution-supplied functions such as require.  So let me rephrase my original questions and we'll just stick to require only:

Is there some reason accepting     require("file", "ignored argument")     is a language feature?  Some use-case I don't see?  (If so, why is there the occasional check for extra arguments?)

Is it documented somewhere I missed that lua functions supplied by the distribution accept and ignore extra arguments?

Is there any reason not to add checks for extra arguments to the functions supplied by the lua distribution?  If it's performance, it could be available as a compile time option.

I hope this gets the discussion back on track, whether anyone agrees with me or not.

Thanks,
Keni
Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Thijs Schreijer


> On 27 Jun 2018, at 13:15, Kenneth Lorber <[hidden email]> wrote:
>
>> On 26 Jun 2018, at 13:13, Kenneth Lorber <[hidden email]<mailto:[hidden email]>> wrote:
>>
>> On Jun 23, 2018, at 8:57 AM, Andrew Gierth <[hidden email]<mailto:[hidden email]>> wrote:
>>
>> [...]
>> To me it is about flexibility, multiple return values, and the ability to only take what is needed. Eg:
>>
>>   take_two(return_three())
>>
>> Without a bunch of locals. Why would you even want to limit that and make it an error? It takes flexibility away.
>>
>> For example: take OpenResty, it uses a lot of those extra checks and it's a pita. See this code for example:
>>
>> https://github.com/Kong/kong/blob/82a51c4b519728eed4f957fdaa547ed4abea9332/kong/globalpatches.lua#L296-L302
>>
>> The last argument “socket options” must be a table, not even `nil` is accepted. Hence in the calling code it requires an if-then construct.
>>
>> So be careful what you wish for with those checks.
>>
>> Thijs
>
> I was going to just let this go, but the replies are getting so far afield I just can't.  I'm not asking about the language feature in general, or about function prototypes, or  user written code or any of the other things people have brought up.
>
> I'm talking about the basic, lua-distribution-supplied functions such as require.  So let me rephrase my original questions and we'll just stick to require only:
>
> Is there some reason accepting     require("file", "ignored argument")     is a language feature?  Some use-case I don't see?  (If so, why is there the occasional check for extra arguments?)
>
> Is it documented somewhere I missed that lua functions supplied by the distribution accept and ignore extra arguments?
>
> Is there any reason not to add checks for extra arguments to the functions supplied by the lua distribution?  If it's performance, it could be available as a compile time option.
>
> I hope this gets the discussion back on track, whether anyone agrees with me or not.
>
> Thanks,
> Keni

The way I see it, Lua tries to be as “unspecific” as possible, as in that the global environment itself is just a table for example, as are all libraries, and the registry, and every global can be redefined by a Lua version.

In your example `require` is just a function, as any other Lua function. With your proposal you’re defining “Lua defined functions” and “language defined functions” as separate types/behaviours. Why this complication?

Thijs
Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Sean Conner
In reply to this post by Kenneth Lorber
It was thus said that the Great Kenneth Lorber once stated:

> > On Jun 23, 2018, at 8:57 AM, Andrew Gierth <[hidden email]> wrote:
> >
> > Pretty much every function accepts and silently ignores extra arguments,
> > unless the function itself bothers to check for them and throw an
> > explicit error.
>
> Thanks, and after a little source diving you are correct, but that's not
> quite the reply I was looking for.
>
> Is there some reason this is a language feature?  Some use-case I don't
> see?  (If so, why is there the occasional check for extra arguments?)

  It's not just Lua.  Here's an example in C:

        ----[ x.c ]------
        #include <stdio.h>
       
        extern int foo();
       
        int main(void)
        {
          int x = foo(1,2,3,4,5);
          printf("%d\n",x);
          return 0;
        }


        ----[ y.c ]-----
        extern foo(int,int); // to shut up clang

        int foo(int a,int b)
        {
          return a + b;
        }

[spc]dynamic-147:/tmp>gcc -ansi -pedantic -Wall -Wextra x.c y.c
[spc]dynamic-147:/tmp>clang -ansi -pedantic -Wall -Wextra -Weverything x.c y.c
[spc]dynamic-147:/tmp>./a.out
3

  No warnings.  No errors.  I'm passing way more parameters to foo() than it
is expecting.  And it works.  Granted, I'm using an outdated style of
function prototype which in C means "this function takes an unspecified
number of arguments and returns an integer" (at least in x.c; y.c has the
proper prototype, but that's to shut up clang about a missing function
prototype that GCC doesn't report).

> Is it documented somewhere I missed?
>
> Is there any reason not to add checks for extra arguments?  If it's
> performance, it could be available as a compile time option.

  It's performance, and it doesn't hurt.  I'm also not sure how easy it
would be to catch at compile time.

  -spc

Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Luiz Henrique de Figueiredo
In reply to this post by Kenneth Lorber
If you want to be strict, use code like this:

function check(t,...)
        local a=table.pack(...)
        assert(#t==a.n, #t.." arguments expected")
        for i=1,a.n do
                assert(t[i]==a[i],"arg #"..i.." expected to be "..t[i])
        end
end

local function strict(f,t)
        return function (...)
                check(t,...)
                return f(...)
        end
end

require=strict(require,{ "string"})

require(23)
require("a","oops")

Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Kenneth Lorber
In reply to this post by Kenneth Lorber


On Jun 27, 2018, at 9:51 AM, [hidden email] wrote:

Date: Wed, 27 Jun 2018 12:06:41 +0000
From: Thijs Schreijer <[hidden email]>
Subject: Re: require() parse error in 5.3.4/5.4.0-work2?
To: Lua mailing list <[hidden email]>
Message-ID: <[hidden email]>
Content-Type: text/plain; charset="utf-8"



On 27 Jun 2018, at 13:15, Kenneth Lorber <[hidden email]> wrote:

On 26 Jun 2018, at 13:13, Kenneth Lorber <[hidden email]<mailto:[hidden email]>> wrote:

On Jun 23, 2018, at 8:57 AM, Andrew Gierth <[hidden email]<mailto:[hidden email]>> wrote:

[...]
To me it is about flexibility, multiple return values, and the ability to only take what is needed. Eg:

 take_two(return_three())

Without a bunch of locals. Why would you even want to limit that and make it an error? It takes flexibility away.

For example: take OpenResty, it uses a lot of those extra checks and it's a pita. See this code for example:

https://github.com/Kong/kong/blob/82a51c4b519728eed4f957fdaa547ed4abea9332/kong/globalpatches.lua#L296-L302

The last argument “socket options” must be a table, not even `nil` is accepted. Hence in the calling code it requires an if-then construct.

So be careful what you wish for with those checks.

Thijs

I was going to just let this go, but the replies are getting so far afield I just can't.  I'm not asking about the language feature in general, or about function prototypes, or  user written code or any of the other things people have brought up.

I'm talking about the basic, lua-distribution-supplied functions such as require.  So let me rephrase my original questions and we'll just stick to require only:

Is there some reason accepting     require("file", "ignored argument")     is a language feature?  Some use-case I don't see?  (If so, why is there the occasional check for extra arguments?)

Is it documented somewhere I missed that lua functions supplied by the distribution accept and ignore extra arguments?

Is there any reason not to add checks for extra arguments to the functions supplied by the lua distribution?  If it's performance, it could be available as a compile time option.

I hope this gets the discussion back on track, whether anyone agrees with me or not.

Thanks,
Keni

The way I see it, Lua tries to be as “unspecific” as possible, as in that the global environment itself is just a table for example, as are all libraries, and the registry, and every global can be redefined by a Lua version.

In your example `require` is just a function, as any other Lua function. With your proposal you’re defining “Lua defined functions” and “language defined functions” as separate types/behaviours. Why this complication?

Thijs

Since we are clearly not communicating effectively, let's try this from another direction:
> math.random(3,4,5)
stdin:1: wrong number of arguments

> t={}
> table.insert(t,1,2,3,4)
stdin:1: wrong number of arguments to 'insert'

Are these bugs that should be fixed in Lua?


Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Doug Currie
On Wed, Jun 27, 2018 at 4:32 PM Kenneth Lorber <[hidden email]> wrote:
[...]

Are these bugs that should be fixed in Lua?

No.

Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Stephen Irons-3
In reply to this post by Kenneth Lorber


On Thu, Jun 28, 2018 at 8:31 AM, Kenneth Lorber <[hidden email]> wrote:

>>
>>
>> On Jun 27, 2018, at 9:51 AM, [hidden email] wrote:
>>
>> Date: Wed, 27 Jun 2018 12:06:41 +0000
>> From: Thijs Schreijer <[hidden email]>
>> Subject: Re: require() parse error in 5.3.4/5.4.0-work2?
>> To: Lua mailing list <[hidden email]>
>> Message-ID: <[hidden email]>
>> Content-Type: text/plain; charset="utf-8"
>>
>>
>>
>>> On 27 Jun 2018, at 13:15, Kenneth Lorber <[hidden email]> wrote:
>>>
>>>> On 26 Jun 2018, at 13:13, Kenneth Lorber
>>>> <[hidden email]<mailto:[hidden email]>> wrote:
>>>>
>>>> On Jun 23, 2018, at 8:57 AM, Andrew Gierth
>>>> <[hidden email]<mailto:[hidden email]>>
>>>> wrote:
>>>>
>>>> [...]
>>>> To me it is about flexibility, multiple return values, and the
>>>> ability to only take what is needed. Eg:
>>>>
>>>>  take_two(return_three())
>>>>
>>>> Without a bunch of locals. Why would you even want to limit that
>>>> and make it an error? It takes flexibility away.
>>>>
>>>> For example: take OpenResty, it uses a lot of those extra checks
>>>> and it's a pita. See this code for example:
>>>>
>>>> https://github.com/Kong/kong/blob/82a51c4b519728eed4f957fdaa547ed4abea9332/kong/globalpatches.lua#L296-L302
>>>>
>>>> The last argument “socket options” must be a table, not even
>>>> `nil` is accepted. Hence in the calling code it requires an
>>>> if-then construct.
>>>>
>>>> So be careful what you wish for with those checks.
>>>>
>>>> Thijs
>>>
>>> I was going to just let this go, but the replies are getting so far
>>> afield I just can't.  I'm not asking about the language feature in
>>> general, or about function prototypes, or  user written code or any
>>> of the other things people have brought up.
>>>
>>> I'm talking about the basic, lua-distribution-supplied functions
>>> such as require.  So let me rephrase my original questions and
>>> we'll just stick to require only:
>>>
>>> Is there some reason accepting     require("file", "ignored
>>> argument")     is a language feature?  Some use-case I don't see?  
>>> (If so, why is there the occasional check for extra arguments?)
>>>
>>> Is it documented somewhere I missed that lua functions supplied by
>>> the distribution accept and ignore extra arguments?
>>>
>>> Is there any reason not to add checks for extra arguments to the
>>> functions supplied by the lua distribution?  If it's performance,
>>> it could be available as a compile time option.
>>>
>>> I hope this gets the discussion back on track, whether anyone
>>> agrees with me or not.
>>>
>>> Thanks,
>>> Keni
>>
>> The way I see it, Lua tries to be as “unspecific” as possible,
>> as in that the global environment itself is just a table for
>> example, as are all libraries, and the registry, and every global
>> can be redefined by a Lua version.
>>
>> In your example `require` is just a function, as any other Lua
>> function. With your proposal you’re defining “Lua defined
>> functions” and “language defined functions” as separate
>> types/behaviours. Why this complication?
>>
>> Thijs
>
> Since we are clearly not communicating effectively, let's try this
> from another direction:
> > math.random(3,4,5)
> stdin:1: wrong number of arguments
>
> > t={}
> > table.insert(t,1,2,3,4)
> stdin:1: wrong number of arguments to 'insert'
>
> Are these bugs that should be fixed in Lua?
>
>

>

You bring up the point that some functions in the 'standard' Lua
libraries check the number and/or type of parameters while others do
not.

* t = require('table', 1234)   -- second parameter is silently ignored
* n = math.random(1, 10, 100)  -- third parameter causes function to
throw an error
* table.insert(t, 1, 2, 3, 4) -- fourth parameter causes function to
throw an error; also if zero or one parameters

You then ask

* whether there is a reason for this difference
* is it a bug in Lua (the language)
* is it a bug in one or more of the standard Lua library functions (I
added this alternative place for a bug)
* if so, do they need to be fixed

I suspect that the difference in behaviour is due to implementation,
with a bit of history and inertia.

'require()' checks that the first parameter is a string (after
coertion), but does no other parameter checking. It would take
additional code to check for the number of parameters passed in.

'math.random()' have three behaviours depending on whether the caller
pass zero, one or two parameters. It throws an error (a fourth
behaviour) for any more than two parameters. The function is written in
C and uses a switch statement on the number of parameters to decide
what to do. It is trivial to provide a 'default' case to throw an error
for more than two parameters.

'table.insert()' has two behaviours depending on whether the caller
pass two or three parameters. It throws an error (a third behaviour)
for zero, one or more than three parameters. The function is written in
C and uses a switch statement on the number of parameters to decide
what to do. It is trivial to provide a 'default' case to throw an error
for the wrong number of parameters.

By design, Lua (the language) does not check that a function call
provides the correct number or type of parameter. This allows lots of
useful things.

If a function wants to check its parameters, standard Lua operations
are available to do so, but each function must do its own checks.

My conclusion is that there is definitely not a bug in Lua (the
language).

The next question is whether there is a bug in one or more of the
library functions.

* Should 'require()' (and any other function that silently ignores
extra parameters) throw an error?
* Should 'math.random()' (and any other function that throws an error
for extra parameters) silently ignore them?
* Should standard library functions be consistent in the way they
handle extra parameters?
* Should someone put in the effort to make it so?

There is no easy answer to these questions. The rest that follows is my
opinion.

I would prefer that functions silently accept extra parameters, like
Lua (the language).

I would be happy if 'math.random()' silently accepted 3 or more
parameters. It would seem to be trivial to implement, with the
'default:' case in the switch doing the same as 'case 3:', but I
suspect my quick look at the code has ignored the size of the stack or
something.

It is slightly more difficult for table.insert(). The error case would
have to be restricted to zero and one parameters. The 'default:' case
would do the same as 'case 3:', but, once again, I have probably
overlooked something.

In any case, changing the code will mean someone has to spend the time
to look at these issues.

Silently accepting extra parameters might make learning the language or
the library functions more difficult. It might make debugging problems
more difficult. I have not looked at all places where functions throw
an error on extra parameters.

It is almost certain that if any of the standard library functions
changed to the other 'mode', someone's software would break. It is
absolutely certain that somebody's expectations would break, because it
would be different from before. Someone will complain.

It is almost certain that someone else will ask the same question about
consistency if the standard library functions do not become consistent
in the way they handle extra parameters.

It would be nice on some level if there was consistency in the standard
library functions; my preference (which, surprisingly, has not changed
over a few paragraphs) would be to silently accept extra parameters,
the Lua way.

Overall, however, I would prefer that the implementors of Lua and the
standard library functions continued working on important language
issues, rather than fixing minor inconsistencies in already working
code.

Stephen Irons




Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Dirk Laurie-2
In reply to this post by Kenneth Lorber
2018-06-27 22:31 GMT+02:00 Kenneth Lorber <[hidden email]>:

> Since we are clearly not communicating effectively, let's try this from
> another direction:
>> math.random(3,4,5)
> stdin:1: wrong number of arguments
>
>> t={}
>> table.insert(t,1,2,3,4)
> stdin:1: wrong number of arguments to 'insert'
>
> Are these bugs that should be fixed in Lua?

No.

A bug is behaviour that differs from the documentation: if you do as
the manual says and something different happens, that would be a bug.

By and large the manual leaves undocumented what happens at the Lua
level if you fail to do as the manual says. Whatever it does is then
by definition not a bug.

Roberto himself has said [1]: 'Please stop calling "bug" something
that does not behave as you wanted
or imagined.'

[1] http://lua-users.org/lists/lua-l/2013-04/msg00825.html

Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Kenneth Lorber
In reply to this post by Kenneth Lorber
> From: Dirk Laurie <[hidden email]>
>
>> Are these bugs that should be fixed in Lua?
>
> No.
> [...]

Ok, good argument for this being a change request and not a bug report.


> From: Stephen Irons <[hidden email]>
> You bring up the point that some functions in the 'standard' Lua
> libraries check the number and/or type of parameters while others do
> not.
>
> * t = require('table', 1234)   -- second parameter is silently ignored
> * n = math.random(1, 10, 100)  -- third parameter causes function to
> throw an error
> * table.insert(t, 1, 2, 3, 4) -- fourth parameter causes function to
> throw an error; also if zero or one parameters
>
> You then ask
>
> * whether there is a reason for this difference
> * is it a bug in Lua (the language)
> * is it a bug in one or more of the standard Lua library functions (I
> added this alternative place for a bug)
> * if so, do they need to be fixed
>
> I suspect that the difference in behaviour is due to implementation,
> with a bit of history and inertia.
>
> 'require()' checks that the first parameter is a string (after
> coertion), but does no other parameter checking. It would take
> additional code to check for the number of parameters passed in.
>
> 'math.random()' have three behaviours depending on whether the caller
> pass zero, one or two parameters. It throws an error (a fourth
> behaviour) for any more than two parameters. The function is written in
> C and uses a switch statement on the number of parameters to decide
> what to do. It is trivial to provide a 'default' case to throw an error
> for more than two parameters.
>
> 'table.insert()' has two behaviours depending on whether the caller
> pass two or three parameters. It throws an error (a third behaviour)
> for zero, one or more than three parameters. The function is written in
> C and uses a switch statement on the number of parameters to decide
> what to do. It is trivial to provide a 'default' case to throw an error
> for the wrong number of parameters.
>
> By design, Lua (the language) does not check that a function call
> provides the correct number or type of parameter. This allows lots of
> useful things.
>
> If a function wants to check its parameters, standard Lua operations
> are available to do so, but each function must do its own checks.
>
> My conclusion is that there is definitely not a bug in Lua (the
> language).

Agreed.

>
> The next question is whether there is a bug in one or more of the
> library functions.
>
> * Should 'require()' (and any other function that silently ignores
> extra parameters) throw an error?
> * Should 'math.random()' (and any other function that throws an error
> for extra parameters) silently ignore them?
> * Should standard library functions be consistent in the way they
> handle extra parameters?
> * Should someone put in the effort to make it so?
>
> There is no easy answer to these questions. The rest that follows is my
> opinion.
>
> I would prefer that functions silently accept extra parameters, like
> Lua (the language).
>
> I would be happy if 'math.random()' silently accepted 3 or more
> parameters. It would seem to be trivial to implement, with the
> 'default:' case in the switch doing the same as 'case 3:', but I
> suspect my quick look at the code has ignored the size of the stack or
> something.
>
> It is slightly more difficult for table.insert(). The error case would
> have to be restricted to zero and one parameters. The 'default:' case
> would do the same as 'case 3:', but, once again, I have probably
> overlooked something.
>
> In any case, changing the code will mean someone has to spend the time
> to look at these issues.

I did.  It took about 6 hours for a prototype implementation.  Someone who
knows lua internals better than I do should be able to do it in half that.

>
> Silently accepting extra parameters might make learning the language or
> the library functions more difficult. It might make debugging problems
> more difficult. I have not looked at all places where functions throw
> an error on extra parameters.

Debugging problems is how I noticed this issue.  A misplaced parenthesis
was very hard to find.

>
> It is almost certain that if any of the standard library functions
> changed to the other 'mode', someone's software would break.

I have the luxury of starting a project from scratch, so I can accept
that breakage.  That leaves the question of how many bugs would be found
versus how much actual breakage would occur.  It's an interesting experiment
I will leave to others.

> It is
> absolutely certain that somebody's expectations would break, because it
> would be different from before. Someone will complain.

Clearly!

>
> It is almost certain that someone else will ask the same question about
> consistency if the standard library functions do not become consistent
> in the way they handle extra parameters.
>
> It would be nice on some level if there was consistency in the standard
> library functions; my preference (which, surprisingly, has not changed
> over a few paragraphs) would be to silently accept extra parameters,
> the Lua way.
>
> Overall, however, I would prefer that the implementors of Lua and the
> standard library functions continued working on important language
> issues, rather than fixing minor inconsistencies in already working
> code.

As a developer, I want all the help I can get.  When C added prototypes,
they broke some working code, added some work for the developer, and found
(and prevented) a LOT of bugs.  When Perl added prototypes, the effect wasn't
as great.  One of the major differences is that having prototypes found lots
of issues when calling C standard library functions - things that are hard to
find without the source to those functions since a debugger can't help.  Perl
has always checked the number of arguments to its built-in functions, so that
situation didn't change.  The case for lua is more like the C case - there is
no good way of detecting this type of error from lua.

(Someone pointed out that I can redefine require to check its arguments before
calling the original require.  That has a tremendous amount of overhead and
is probably harder to write than the C version.  Not to mention as an external
tool you would have to remember to actually use it.  So I don't consider this
a good solution.  Others will certainly have different tradeoffs for their projects.)

I'm not advocating (or even discussing) a general prototype system - that's clearly
a very complex change with some heavy costs involved.

So to put some alpha quality code where my mouth is, there is now a copy
of what I have at the moment at https://github.com/nhkeni/lua/tree/keni-argcount

Thanks,
Keni


Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Sam Putman
In reply to this post by Stephen Irons-3


On Wed, Jun 27, 2018 at 9:20 PM, Stephen Irons <[hidden email]> wrote:

'require()' checks that the first parameter is a string (after coertion), but does no other parameter checking. It would take additional code to check for the number of parameters passed in.


I would strongly prefer that it continue to exhibit this behavior. 

I don't yet have the need, but this allows for a re-written require like so

local library = require ("library", ">0.3")

and so on. This would continue to work in contexts which haven't extended require.
Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Dirk Laurie-2
Overall, however, I would prefer that the implementors of Lua and the
standard library functions continued working on important language
issues, rather than fixing minor inconsistencies in already working
code.2018-07-01 20:47 GMT+02:00 Sam Putman <[hidden email]>:

> I would strongly prefer that it continue to exhibit this behavior.
>
> I don't yet have the need, but this allows for a re-written require like so
>
> local library = require ("library", ">0.3")
>
> and so on. This would continue to work in contexts which haven't extended
> require.

Your reason is not convincing. if you monkey-patch a system function,
and rely on its patched behaviour, you should test that it behaves as
desired. That re-written 'require' presumably errors when the second
argument does not conform the desired syntax. So you pcall it right at
the start of your file and check that it does.

However, I agree with your preference, on the simpler grounds that if
it ain't broke, don't fix it. By Murphy's law, somewhere out there is
a program that has worked for years (probably without a current
maintainer) that will now break.

Anyway, it matters enough to Keni that he wrote a patch, so it's now
up to those who feel likewise to apply that patch and gain some
experience in how they like it.

BTW, I myself use a require patch that I have advertised on this list,
that allows you to say

$ lua -l json=cjson myprog.lua

I.e. you can switch on the command line between different libraries
with the same interface.

It has not yet set the Thames on fire.

-- Dirk

Reply | Threaded
Open this post in threaded view
|

Re: require() parse error in 5.3.4/5.4.0-work2?

Soni "They/Them" L.


On 2018-07-02 05:30 AM, Dirk Laurie wrote:

> Overall, however, I would prefer that the implementors of Lua and the
> standard library functions continued working on important language
> issues, rather than fixing minor inconsistencies in already working
> code.2018-07-01 20:47 GMT+02:00 Sam Putman <[hidden email]>:
>
>> I would strongly prefer that it continue to exhibit this behavior.
>>
>> I don't yet have the need, but this allows for a re-written require like so
>>
>> local library = require ("library", ">0.3")
>>
>> and so on. This would continue to work in contexts which haven't extended
>> require.
> Your reason is not convincing. if you monkey-patch a system function,
> and rely on its patched behaviour, you should test that it behaves as
> desired. That re-written 'require' presumably errors when the second
> argument does not conform the desired syntax. So you pcall it right at
> the start of your file and check that it does.
>
> However, I agree with your preference, on the simpler grounds that if
> it ain't broke, don't fix it. By Murphy's law, somewhere out there is
> a program that has worked for years (probably without a current
> maintainer) that will now break.
>
> Anyway, it matters enough to Keni that he wrote a patch, so it's now
> up to those who feel likewise to apply that patch and gain some
> experience in how they like it.
>
> BTW, I myself use a require patch that I have advertised on this list,
> that allows you to say
>
> $ lua -l json=cjson myprog.lua
>
> I.e. you can switch on the command line between different libraries
> with the same interface.
>
> It has not yet set the Thames on fire.
>
> -- Dirk
>

In practice:

require(re.match(s, "(idk(or|other)(etc)+)"))

ofc this assumes you have a real regex module, and it can easily be
fixed by using non-capturing groups.