Arc Forumnew | comments | leaders | submitlogin
Why table ?
4 points by proponent 5557 days ago | 15 comments
Both (table) and (obj) return empty hash tables, right? So why is table needed at all?


3 points by conanite 5557 days ago | link

obj is a macro for creating tables inline that internally uses table

  arc> (obj a 1 b 2)
  #hash((b . 2) (a . 1))
  arc> (table)
  #hash()
table takes an optional initialiser function,

  arc> (table [= _!a 1 _!b 2])
  #hash((b . 2) (a . 1))
so they are different ways of initialising tables.

-----

2 points by proponent 5557 days ago | link

Thank you; I had been unaware of the optional initialiser argument to table .

-----

2 points by proponent 5548 days ago | link

Some follow-up questions.... Suppose we invoke table with an initialiser function. If I understand correctly, the argument that will be passed to the initialiser is always going to be an empty table. That would seem to make the initialiser not very useful. I suppose what I'm saying is that it doesn't seem very useful to have table visible in Arc, even if it is useful in the underlying Scheme implementation; couldn't it just be eliminated from the language, making it simpler with no loss of functionality? What am I missing?

Next question: I'm no Scheme expert, but the definition of table in ac.scm doesn't seem to allow for any optional arguments:

(xdef table (lambda args (let ((h (make-hash-table 'equal))) (if (pair? args) ((car args) h)) h)))

So how does the optional initialiser get used?

Finally, why is obj called obj? I would guess its short for "object", but all kinds of things are objects. I hope this doesn't sound like I'm whining; I'm just trying to develop maximally coherent understanding of Arc, which I like very much.

-----

3 points by palsecam 5548 days ago | link

> That would seem to make the initialiser not very useful. / how does the optional initialiser get used?

The initialiser can fill the table.

  arc> (table [for i 0 5 (= _.i (* i i))])
  #hash((3 . 9) (4 . 16) (5 . 25) (0 . 0) (1 . 1) (2 . 4))
For more practical examples, you can `grep' news.arc.

> (xdef table (lambda args (let ((h (make-hash-table 'equal))) (if (pair? args) ((car args) h)) h)))

Scheme (lambda args ...) is equivalent to Arc (fn args ...).

It allows to get the raw list of arguments, which may be empty (i.e: no arguments are passed).

So (if (pair? args) ((car args) h)) h) tests if args is a non-empty list (with pair?). If so, it uses the car of this list as the initialiser. It calls it (((car args) h)) with the freshly created table, h, as parameter.

(An example of the "raw arguments list" behaviour in Arc:

   arc> (def prnargs args  ; /!\ no parents around "args"
          (forlen i args (prn "arg n°" i ": " (args i))))
   arc> (prnargs)
   nil
   arc> (prnargs 'a 'b)
   arg n°0: a
   arg n°1: b
   nil
)

> ... removing table / obj > table ...

I believe 'obj is less used than 'table. 'table is more simple in that everyone knows what a (hash)table is, but an "object" is a fuzzy concept, as you pointed it out.

> but all kind of things are objects

Yep, and what most people call objects are more/less just a more/less "special" hashtable. That's why, I suppose, obj is called like that: just a synonym for table (although the function 'obj is != from 'table).

You can do a lot with an hashtable, and it's cool. Where is the problem?

(For info, Arc's templates also uses hashtables behind the hood, if I remember well. See also: Javascript objects.)

> I suppose what I'm saying is that it doesn't seem very useful to have table visible in Arc and in general

I agree with you that maybe having both 'obj and 'table is a bit confusing, and maybe too much. People may expect they are totally different things. And they are in a way redundant.

My quick idea would be to make 'table takes 0, 1 or more args. If 0, empty hash. If 1, it's an initialiser fn. If more it uses the args like 'obj does.

-----

1 point by absz 5548 days ago | link

As I observed above (http://arclanguage.org/item?id=10528), table can't do this (unless we rotate names around, which would be a perfectly valid option), but here's a lightly-tested macro (with a terrible name) which exhibits your DWIMmy behaviour:

  (mac amphi-table args
    (cons (if (<= (len args) 1) 'table 'obj) args))

-----

2 points by proponent 5547 days ago | link

Thank you. Somehow how I missed your earlier reply.

-----

2 points by absz 5547 days ago | link

That would probably be because I made my two replies about five minutes apart :)

-----

2 points by proponent 5548 days ago | link

Thanks much for your detailed and informative reply. I like your suggestion about changing to 'table to take variable numbers of arguments.

-----

2 points by palsecam 5546 days ago | link

> I like your suggestion about changing to 'table to take variable numbers of arguments.

Then let's do it :-)

In ac.scm, we change the xdef of 'table, and the def of 'fill-table (which doesn't seem to be used anymore) to work with a normal list (and not an alist).

   (xdef table (lambda args
	         (let ((h (make-hash-table 'equal)))
		   (if (pair? args)
		       (if (pair? (cdr args))
			   (fill-table h args)
			   ((car args) h)))
		   h)))

   (define (fill-table h lst)
     (if (pair? lst)
         (begin (hash-table-put! h (car lst) (cadr lst))
	        (fill-table h (cddr lst)))
         h))
Then we have what we want:

  arc> (table)
  #hash()
  arc> (table [for i 0 3 (= _.i 42)])
  #hash((3 . 42) (0 . 42) (1 . 42) (2 . 42))
  arc> (table 'a 2 'b 42)
  #hash((b . 42) (a . 2))
(Warning: lightly tested)

> Thanks much for your detailed and informative reply.

Thanks go to you for having a fresh view on the data structures of Arc, and questioning them. I was just "quoting the manual" and this is not hard.

----

To absz: thanks for mentioning "DWIM", I didn't know this acronym but this is exactly what I expect from a (programming) language. It is what differenciates a language from a (formal) notation IMO. Funny point, the (french) wikipedia article uses Perl as a DWIM-oriented language example :-)

Interesting that Thaddeus (http://www.arclanguage.org/item?id=10533) makes a mistake using 'obj / wants 'inst to work w/ 'obj. This comforts me in the idea that 'obj is confusing. People expects an "object" to do magic (inheritance, instanciation, etc), to be high-level, where they just expect an (hash)"table" to be a simple key/value store.

The DWIM definition of 'table given above would be even better if it could also take an alist as single argument, and use it to init the table (it's easily doable, but I'm tired now).

-----

1 point by palsecam 5545 days ago | link

But maybe this DWIM stuff is crap because we're writing everything in Scheme and not in Arc.

Maybe (xdef new-table (lambda () (make-hash-table 'equal)), and then use the raw 'new-table and 'fill-table, 'listtab, 'tablist and co. to define a DWIM 'table in Arc.

Or maybe it's crap because DWIM is crap by nature and it's better to have (to know) 'table, 'obj, 'fill-table, etc.

What is sure is that it makes the "design work" easier, you can keep the 'table/etc. definitions shorter and cleaner in arc.arc/etc. What is less sure is if doing so (making the designer have the good life) is the way to have a pratical language for actual programmers.

-----

1 point by conanite 5545 days ago | link

I like your definition of table. The only advantage of 'obj is that keys don't need to be quoted. (Although sometimes that's a disadvantage too; the macro quotes them, so keys can't be determined at run-time)

-----

1 point by thaddeus 5546 days ago | link

> "Finally, why is obj called obj?"

I like "obj". After all in OOP isn't an object simply a property list of key/value pairs with initial values set to define the object?

   i.e.

   (= vampire (obj teeth "fangs" hair "black" food "blood"))

   (= Dracula vampire)

 So now we have an instance named "Dracula" of a "vampire" object....  
or maybe I'm on glue thinking this was the intent.... T.

-----

2 points by conanite 5546 days ago | link

I share your guess that 'obj is a contraction of "object". I don't think it means exactly what your example suggests. Continuing your example, if you write

  (= conanite vampire)
, the symbols 'vampire, 'conanite and 'Dracula all refer to the same object instance, so it's probably not what you want. In other words, you can turn conanite's hair blue like this:

  (= Dracula!hair 'blue) ; *not tested*
I don't know if it's the glue, but I think 'deftem ("define template") and 'inst ("instantiate template") do what you describe here.

  (deftem vampire name nil fangs 2 hair 'black requires 'blood) ; sorry, my vampire is defined a little differently
'deftem sorta kinda creates a "class" - but only with data slots, no behaviour.[1] Now, if you want to call up some vampires,

  (= Dracula (inst 'vampire 'name "Dracula"))
  (= conanite (inst 'vampire 'hair 'gray))
inst is pretty similar to obj, except internally it relies on a set of preconfigured "templates" which provide the set of keys (and their default values) for the thing you are going to build. It's used in blog.arc to define blog posts, as well as news.arc to define news items, and user accounts.

[1] at least, not by design, but there's nothing to stop you from assigning a function as the default value of any slot; except then it couldn't really be written to disk ...

-----

2 points by thaddeus 5546 days ago | link

Ah... you're correct. I was thinking of the inst behaviour.

Too bad the following doesn't work:

   arc> (= vampire (obj teeth "fangs" hair "black" food "blood"))
   #hash((hair . "black") (food . "blood") (teeth . "fangs"))
   arc> (= Dracula (inst 'vampire))
   #hash()
Thanks for the correction... (haven't worked on arc for a few weeks :) T.

-----

2 points by absz 5548 days ago | link

Because obj is a macro, and without table, what would obj expand into?

-----