lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]




On 2019-07-31 6:09 p.m., Egor Skriptunoff wrote:
On Wed, Jul 31, 2019 at 7:07 AM Soni "They/Them" L. wrote:


    Cratera is a language very similar to Lua, and as such most of the
    Lua
    manual applies to it. Additionally, it supports the following syntax
    sugar, called "traits":

         mytable:[mytrait].myfunction(myargument)

    which is equivalent to:

         mytable[mytrait].myfunction(mytable, myargument)



1)
Is this feature really needed?
Please show an example.

This is heavily inspired by Rust traits. In Rust, you can do something like:

fn main() {
    let v = <Vec<_> as From<&str>>::from("hello, world!");
    println!("{:?}", v);
}

(However, in this case you're using "<Type as Trait>::function()". I don't know why Rust doesn't support "<binding as Trait>.method()" but I had to adapt this whole thing.)

You can also call methods from traits using the object. I took these ideas and adapted them for a dynamic programming language like Lua.

It's just a different way of doing OOP. Since Lua prides itself on having many ways of doing OOP as long as you implement them yourself (you can have classes in Lua, but you can also have prototype-based OOP, but you can also have even other forms of OOP. some of those are more or less efficient than others.), I decided to implement trait-based OOP as efficiently as I knew how - with a language extension.

You can see a small example in tests.cratera (see below). However, keep in mind it was my first cratera example and I hadn't fully worked out how you should be doing things in cratera - I wouldn't do it exactly like that nowadays. But it does capture the basic idea.

--------
-- example from tests.cratera

entity = {}

inventory = {get=false, set=false, size=false}
inventory.new=function(size)
  local t = {size=function() return size end}
  function t.set(e, i, o)
    if i <= 0 or i > e:[inventory].size() then error() end
    e[inventory][i] = o
  end
  function t.get(e, i)
    if i <= 0 or i > e:[inventory].size() then error() end
    return e[inventory][i]
  end
  return t
end
inventory.of=function(e) -- helper for passing standalone inventories around
  return {get=function(...)return e:[inventory].get(...)end, set=function(...)return e:[inventory].set(...)end, size=function(...)return e:[inventory].size(...)end}
end

entity[inventory] = inventory.new(5)

entity:[inventory].set(1, "Hello World!")

print(entity:[inventory].get(1))

for i=1, entity:[inventory].size() do
  print(i, entity:[inventory].get(i))
end

local myinv = inventory.of(entity)

for i=1, myinv.size() do
  print("wrapped", i, myinv.get(i))
end
--------


2)
Am I able to invoke a method by its name from a variable in Cratera?
   local methodname = "close"
   file:[methodname]()


No. While that was implemented in the Cratera patchset, it's not implemented in Cratera Compiler. Cratera is implemented with a function by Cratera Compiler, and to support this syntax I'd need another function. Given the usefulness of this feature for Cratera programs in general (read: nonexistent), I decided against implementing it. It's recommended that you wrap the Lua stdlib to use Cratera OOP if you're writing a Cratera program. Then you'll be able to use:

file:[io].read()
file:[close].close()

3)
Cratera's feature could be generalized further.
The following two simple rules look like a natural extension to Lua syntax:
- There could be multiple colons in a chain
- Each colon means "use current value as extra argument"
Examples:
 a:b[c].f(x)    ->  a.b[c].f(a,  x)
   a.b:[c].f(x)   ->  a.b[c].f(   a.b,   x)
   a.b[c]:f(x)    ->  a.b[c].f(        a.b[c],   x)
   a:b[c]:f(x)    ->  a.b[c].f(a,      a.b[c],   x)
   a.b[c].f:(x)   ->  a.b[c].f(  a.b[c].f, x)
   a:b:[c]:f:(x)  ->  a.b[c].f(a, a.b, a.b[c], a.b[c].f, x)
   c:()           ->  c(c)
It's not a monkey smile in the last line, variable "c" contains a "callable object"


Lua has a nesting limit of 200 or so. a:[b].c() is converted into (CRATERA_FN)(a, b, "c"), which increases the nesting of a and b by one. A normal Lua function chain can go on forever, but Cratera is limited to less than 200 occurrences of traits per statement. If you could use arbitrarily many colons in a chain, that limit would be even lower even quicker.