How about "Luacon", easy constraints?

13 views
Skip to first unread message

Axel Kittenberger

unread,
Jan 19, 2011, 4:08:56 AM1/19/11
to lua-table...@googlegroups.com
Hey guys,

Honoring the goal to make/keep Lua more simple on of the more simple -
that is realistic - ideas is the write a lua constraints module. No
witchcraft, just some module that uses metatables to constraint tables
and thus in the style of defensive programming keep catching errors
early and easy. Constraints is something the user can put up a table
and that will raise an error if violated. In the product they can
easily be removed to minimalst impact by setting constraint =
function() end

constraint(t, "list") -- will error() if any key is no integer and not
from 1..n+1 or a nil is inserted.
constraint(t, "positive keys are list") -- keys that are positive
numeric must be from 1..n+1
constraint(t, "key in {next, foo, bar}") -- a key must be "next" or
"foo" or "bar". Used for 'object' tables, typos raise errors instead
of mysterious nils.
constraint(t, "value is positive") -- all values for t must be
positive integers.
constraint(t, "readonly") -- after this table may not be altered anymore
constraint("no nil globals") -- no global may be nil, any access to an
undefined global will error()
constraint("no new globals") -- after this call no globals may be created.

etc.

This would be a pure lua implementation. I suppose defining its own
grammar as argument is the best I could think of.
I would use it in my project Lsyncd. I started soemthing like this but
somehow let it go, since I didn't wanted to put more effort into the
actual code than the typechecking one.

What do you think about this?

Axel Kittenberger

unread,
Jan 19, 2011, 4:25:24 AM1/19/11
to lua-table...@googlegroups.com

Henning Diedrich

unread,
Jan 19, 2011, 6:10:44 AM1/19/11
to lua table semantics
On Jan 19, 10:08 am, Axel Kittenberger <axk...@gmail.com> wrote:

> What do you think about this?

Pretty cool!

Straight forward, all. If it works and implications become clear, it
may help to do a possible next step.

Best,
Henning

steve donovan

unread,
Jan 19, 2011, 6:23:28 AM1/19/11
to lua-table...@googlegroups.com
On Wed, Jan 19, 2011 at 1:10 PM, Henning Diedrich <hd2...@eonblast.com> wrote:
> On Jan 19, 10:08 am, Axel Kittenberger <axk...@gmail.com> wrote:
>
>> What do you think about this?
>
> Pretty cool!

I agree, a single function for establishing constraints. Entirely
doable I think!

Text rules are fine, providing the grammar is quite clear. Otherwise
one can use a constraint-builder pattern but things then aren't so
simple - text processing really is nice & simple with Lua.

Who wants to do a trial implementation? I will look at what's
involved for Lua 5.1.

This is one approach I had to the problem of 'strict tables' [1]

steve d.

[1] http://lua-users.org/wiki/StrictStructs

steve donovan

unread,
Jan 19, 2011, 8:08:42 AM1/19/11
to lua-table...@googlegroups.com
On Wed, Jan 19, 2011 at 11:08 AM, Axel Kittenberger <axk...@gmail.com> wrote:
> constraint(t, "list") -- will error() if any key is no integer and not
> from 1..n+1 or a nil is inserted.

Here's another spin; a constraint can be on values, keys or both, with
semi-colon as separator - both the domain and range can be
constrained.

So e.g.

"list; positive" ('positive' implies 'number')

"array; table"

"{alpha,beta,gamma}; {number,number,number}"

"list; readonly" (I imagine that ";readonly" means that this is a
value-only constraint)

We're avoiding the traditional and vexing idea of 'classes'; what _is_
lost by not making classes is runtime type info, but I don't know
whether this is really important anyway.

Naturally the constraint() function needs to check whether the
existing table satisfies the constraint, which is a useful side-effect
(like how Dirk checks whether his initial list is free of holes.)

steve d.

Axel Kittenberger

unread,
Jan 19, 2011, 11:03:27 AM1/19/11
to lua-table...@googlegroups.com
I'll try to write a parser. I like writing parsers :-)
Kind regards, Axel

Axel Kittenberger

unread,
Jan 19, 2011, 11:15:10 AM1/19/11
to lua-table...@googlegroups.com
> Here's another spin; a constraint can be on values, keys or both, with
> semi-colon as separator - both the domain and range can be
> constrained.

semicolon as separator is a good idea and easy to implement with gmatch.
> "array; table"
> "{alpha,beta,gamma}; {number,number,number}"

I don't get my head quite around what is ment, not newbie friendly :-)

I see two ways to go I'm not quite sure which is the better one.

One is to have the strings feel somehow "natural language", like "keys
are positive", "values are non-negative", etc.
which has the advantage to be supereasy to read, but the downside that
the "parser-AI" needs to be tought more or less everything you want it
do.

The other is some arithmetic expression that gets parsed and executed
(possibly by the lua parser)
"key >= 0"
"if key < n then condition = key ~=nil end"

where condition is tested to be true or false or if not present the
top most value on stack is used.

I suppose for testing I should try to implement both and see which feels better.
Maybe we can actually do both like either the more "basic sentences" or
"condition: key % 2 == 0" as one valid sentence, where the part after
the doublecolon is parsed and the chunk then executed by lua on every
read/write.

Testing if the existing table fullfills the constraint when applying
to it makes of course a lot of sense.

end - axel

Dirk Laurie

unread,
Jan 19, 2011, 11:26:41 AM1/19/11
to lua-table...@googlegroups.com
On Wed, Jan 19, 2011 at 06:03:27PM +0200, Axel Kittenberger wrote:
> I'll try to write a parser. I like writing parsers :-)
Do you use lpeg or stay with Lua patterns?

D.

steve donovan

unread,
Jan 19, 2011, 11:31:49 AM1/19/11
to lua-table...@googlegroups.com
On Wed, Jan 19, 2011 at 6:15 PM, Axel Kittenberger <axk...@gmail.com> wrote:
>> "array; table"
>> "{alpha,beta,gamma}; {number,number,number}"
> I don't get my head quite around what is ment, not newbie friendly :-)

That's the test of any made-up notation; the WTF factor ;) I meant
that the keys had to be {alpha,beta,gamma} and that the
_corresponding_ types were 'number' etc. That is, specifying a
discrete map. But then why not just
'{alpha=number,beta=number,gamma=number}" - that looks more lua-ish ?

> One is to have the strings feel somehow "natural language", like "keys
> are positive", "values are non-negative", etc.
> which has the advantage to be supereasy to read, but the downside that
> the "parser-AI" needs to be tought more or less everything you want it

It is a little tricky; makes me think about COBOL, which was meant to
make programming as easy as writing English (heh). But in practice
COBOL statements have very particular wording. I still like the idea
of 'plain text' constraints however, although there should be a
limited number of possible sentence structures.

As for parsing expressions; remember that such expressions will also
need to be evaluated at runtime. Can be done efficiently, but
requires dynamic code generation for constraints. I did wonder about
this (i.e 'value > 0' rather than 'value positive') but perhaps then
constraints become over-complicated and hard to understand?

steve d.

PS. parsing stuff is a lot of fun!

steve donovan

unread,
Jan 19, 2011, 11:33:36 AM1/19/11
to lua-table...@googlegroups.com
On Wed, Jan 19, 2011 at 6:26 PM, Dirk Laurie <d...@sun.ac.za> wrote:
> Do you use lpeg or stay with Lua patterns?

I think lpeg is a fine thing, but like Hisham (of LuaRocks fame) I
find that by the time I've wrapped my head around it, I've forgotten
the original problem. String patterns can do all this, without any
external dependencies.

steve d.

Axel Kittenberger

unread,
Jan 19, 2011, 11:36:06 AM1/19/11
to lua-table...@googlegroups.com
Lua patterns, as far as I see the lexer is quite simplistic: one token
is alphanumeric seperated by space characters or "{","}",","
and after its tokenized its parser anyway. It would be mostly on
string comparisons.

Axel Kittenberger

unread,
Jan 19, 2011, 11:38:54 AM1/19/11
to lua-table...@googlegroups.com
hmm, for specific conditions of values for specific keys I'd use a "prototype".
local p = {alpha=number, beta="positive", gamma="string"}
constraint(t, "prototype", p)

steve donovan

unread,
Jan 19, 2011, 11:43:17 AM1/19/11
to lua-table...@googlegroups.com
On Wed, Jan 19, 2011 at 6:38 PM, Axel Kittenberger <axk...@gmail.com> wrote:
> hmm, for specific conditions of values for specific keys I'd use a "prototype".
> local p = {alpha=number, beta="positive", gamma="string"}
> constraint(t, "prototype", p)

That looks good. You can of course overload constraint(t,c) - if c is
a table then it's interpreted as a prototype directly.

Henning Diedrich

unread,
Jan 20, 2011, 2:48:51 AM1/20/11
to lua table semantics
On Jan 19, 5:31 pm, steve donovan <steve.j.dono...@gmail.com> wrote:

> PS. parsing stuff is a lot of fun!

:-)

Would we use the built-in Lua parser for that?

Henning

Axel Kittenberger

unread,
Jan 20, 2011, 3:46:21 AM1/20/11
to lua-table...@googlegroups.com
for conditions yes, otherwise I dont see how "values are positive" can
be made to properly be parsed by lua.
a custom parser that looks for [adjective] (subject) are [not]
(adjective) is easy enough.

So a constraint can be a sentence of the type: [adjective] (subject)
"are" [not] (adjective)

adjectives := positive, negative, strings, integer, tables, in set [table]
subject := keys, values

Or a prototype with keys and values being adjective, thus for every
key->value part of the table the value must fullfill the condition of
the adjective.

Or a condition: starting with "condition:" and the rest is parsed by
the lua parser in the newindex method
where "key" is key "value" is value and "n" is #table.

Dirk Laurie

unread,
Jan 20, 2011, 4:18:56 AM1/20/11
to lua-table...@googlegroups.com
On Thu, Jan 20, 2011 at 10:46:21AM +0200, Axel Kittenberger wrote:
>
> So a constraint can be a sentence of the type: [adjective] (subject)
> "are" [not] (adjective)
>
Hello Cobol, haven't seen you for a long time, thought you were
dead actually.

The assumption if not presumption that someone's English is good
enough to include an accurate distinction between verb forms are
certainly not universally true even among contributors to lua-l.
(Do you think that "are" should have been "is"? Are you sure?)

I can forgive people who do not know Lua for inventing their own
configuration language. But really, whatever words we use for
the constraints, the one skill we are surely entitled to assume
from the user is basic Lua literacy.

So I suggest constraint syntax along the lines of:

strict_lists = true
strict_lists = false
strict_lists = nil -- whatever happens to be the default setting
mysetting = save_constraints() -- save current setting of constraints
reset_constraints() -- reset all constraints to the default setting
reset_constraints(my_setting) -- ... to my_setting

Dirk

steve donovan

unread,
Jan 20, 2011, 4:51:41 AM1/20/11
to lua-table...@googlegroups.com
On Thu, Jan 20, 2011 at 11:18 AM, Dirk Laurie <d...@sun.ac.za> wrote:
> I can forgive people who do not know Lua for inventing their own
> configuration language.  But really, whatever words we use for
> the constraints, the one skill we are surely entitled to assume
> from the user is basic Lua literacy.

This is a good point. The Lua way would look like this:

constraint(t,{
strict_list = true;
values = 'positive'
})

No parsing involved, just a little bit of intelligence to interpret
possible values like 'positive','number',etc. More involved
constraints can be given as an anonymous function.

> mysetting = save_constraints()  -- save current setting of constraints
> reset_constraints()     -- reset all constraints to the default setting
> reset_constraints(my_setting)   -- ... to my_setting

Don't like that - anything that requires mucking around with global
state is going to be awkward and can break in interesting ways.

COBOL is apparently not as dead as we would like. I hear that Java is
the new COBOL, however ;)

steve d.

Dirk Laurie

unread,
Jan 20, 2011, 5:07:55 AM1/20/11
to lua-table...@googlegroups.com
On Thu, Jan 20, 2011 at 11:51:41AM +0200, steve donovan wrote:
> This is a good point. The Lua way would look like this:
>
> constraint(t,{
> strict_list = true;
> values = 'positive'
> })
>
...
> Anything that requires mucking around with global state is going
> to be awkward and can break in interesting ways.
>
True.

Dirk

Axel Kittenberger

unread,
Jan 20, 2011, 5:19:31 AM1/20/11
to lua-table...@googlegroups.com
> This is a good point. The Lua way would look like this:
>
> constraint(t,{
>   strict_list = true;
>   values = 'positive'
> })

Yes true that. That might be better. I dissed this first, since I
considered it a problem every key to be able to present only once, so
what to do with multiple conditions on keys or values? But this can
simply be a subtable.

so valid constraint tables are
{ values = {'positive', 'rule: key % 2 == 0'} } --> all keys are
positive and even

or
{ positive = 'list' } --> all positive keys are a list

or
{ positive_integer = 'list' } --> all positive integer keys are a
list, (e.g. 1.5 is allowed here what isnt in the one before)

or
{ 'c:key % 2' = 'strings' } --> all even keys must be strings

or
{ 'proto' = {'alpha' = 'string', 'beta' = 'string', 'gamma' = string',
[constraint.others] = nil }

alpha, beta, gamma must be strings, no other values allowed. (Not sure
how to make the others syntactically nice)

I dislike globals too. Every table should have its constraints applied
by itself.
What we could think of is an optional core patch that complains/warns
when '#' is called on any table that is not constrained in a list.
Nice for debugging if you dont use libraries that do that.
We too could optionally hijack table.remove and table.insert to make that test.

Henning Diedrich

unread,
Jan 20, 2011, 6:07:47 AM1/20/11
to lua table semantics
> COBOL is apparently not as dead as we would like. I hear that Java is
> the new COBOL, however ;)

Yes, you heard that right.

Henning Diedrich

unread,
Jan 20, 2011, 6:24:12 AM1/20/11
to lua-table...@googlegroups.com, Axel Kittenberger
for conditions yes, otherwise I dont see how "values are positive" can
be made to properly be parsed by lua.
a custom parser that looks for [adjective] (subject) are [not]
(adjective) is easy enough.


I wondered about the syntax used elsewhere.

So far no helpful finds.

A(q)
A(q):-B(q), B(q):-A(q), A(q)
A(q):-B(q), B(q):-A(q), A(q):-B(q), B(q):-A(q), A(q)
http://en.wikipedia.org/wiki/Constraint_logic_programming

Python object driven approach:
http://docs.eveutilities.com/emma/1.0/user_manual/in_depth.html#custom-constraints-queens

Henning

Axel Kittenberger

unread,
Jan 20, 2011, 9:18:46 AM1/20/11
to lua-table...@googlegroups.com
This is an early test just implementing "everything that fullfills
this that must be true" clauses, without yet prototypes or lists.
The example just makes sure all even keys have 0 as value.
Dunno if this syntax makes anything simpler or just looks real complicated :)
luacon.lua

Henning Diedrich

unread,
Jan 20, 2011, 9:46:56 AM1/20/11
to lua-table...@googlegroups.com, Axel Kittenberger
Not so bad for starters!

Henning Diedrich

unread,
Jan 20, 2011, 1:42:26 PM1/20/11
to lua table semantics
On Jan 20, 3:18 pm, Axel Kittenberger <axk...@gmail.com> wrote:
> This is an early test just implementing

I still wonder about syntax. As it goes now it looks helpful but
complicated.

I am all for sugar for this, but really sweet stuff.

Is there any way to make that happen natively?

Best,
Henning

Axel Kittenberger

unread,
Jan 20, 2011, 2:26:26 PM1/20/11
to lua-table...@googlegroups.com
> I still wonder about syntax. As it goes now it looks helpful but
> complicated.

Do you mean complicated in execution or complicated in the user interface?
"Natively" needs a core patch and in my opinion a lua only module
using metatables is more easy on it to get started and accepted.

Kind regards,
Axel

Henning Diedrich

unread,
Jan 20, 2011, 7:35:12 PM1/20/11
to lua table semantics
On Jan 20, 8:26 pm, Axel Kittenberger <axk...@gmail.com> wrote:
> > I still wonder about syntax. As it goes now it looks helpful but
> > complicated.
>
> Do you mean complicated in execution or complicated in the user interface?

The user interface.

> "Natively" needs a core patch and in my opinion a lua only module
> using metatables is more easy on it to get started and accepted.

'Natively', I meant, 'implemented in Lua code', right as it is done
now. I wondered if there was a way to get this to work and look
simpler, in the user interface.

I am less afraid of COBOL I guess.

Maybe it should be a two-layer architecture, where you have the full
liberty like in what you just presented but then there are maximally
simple 'keywords' available to use for the main use cases, which I
thought were few: 'no holes allowed and no non-N keys allowed' =
'strict', else 'associative' (etc).

Henning
Reply all
Reply to author
Forward
0 new messages