Re: Ersatz update: Method references and functional interfaces

2013-03-17 Thread Alexander Burger
On Sun, Mar 17, 2013 at 12:45:32PM -0300, Guillermo R. Palavecino wrote:
> > It is an important feature of PicoLisp that a construct like 'funcall'
> > is NOT needed.
> ...
>   Funcall is not meant for one-liners, it's meant to avoid the horrible
> indentation that ((..) ..) gives in multi-line expressions:

I agree with that. My main concern is just -- as I said -- that the
existence of a function 'funcall' would induce wrong associations for
new users.

♪♫ Alex
-- 
UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe


Re: Ersatz update: Method references and functional interfaces

2013-03-17 Thread Guillermo R. Palavecino
On Sun, 17 Mar 2013 15:18:43 +0100
Alexander Burger  wrote:

> It is an important feature of PicoLisp that a construct like 'funcall'
> is NOT needed.
> 
> One of the fundamental principles of the PicoLisp evaluation
> mechanisms is that the CAR of a list is evaluated, and then used as a
> function.
> 
> Writing
> 
>(de funcall "Args"
>   (eval "Args") )
> 
>(funcall (expression) 3 4)
> 
> is the same as
> 
>(eval '((expression) 3 4))
> 
> instead of
> 
>((expression) 3 4)
> 
> and thus a tautology, just with a considerable overhead.
> 
> 
> Moreover, if you publish code using 'funcall', new users will assume
> this is the right way to do, and use it also in cases like
> 
>(de foo (Fun)
>   (funcall Fun 3 4) )

  You are blowing it out of proportion with that example. It's not like
users will start writing:
 (funcall mapcar pack
(funcall split
   (funcall chop Lst)
   " " ) )

>(dm method> (Arg)
>   (funcall (: hint) Arg) )
>
>(dm method> (Arg)
>   ((: hint) Arg) )

  Funcall is not meant for one-liners, it's meant to avoid the horrible
indentation that ((..) ..) gives in multi-line expressions:

  ((expression that returns a function)
   (the rest of the code
  ((that otherwise would) not look nice when
   (indented in a multi-line layout) ) ) )

where you end up with a case/cond looking layout for normal code (not
to mention what you get if you happen to have (((..) ..) ..) as
multi-line). I like this much better:

  (funcall (expression that returns a function)
 (the rest of the code
(funcall (that otherwise would) not look nice when
   (indented in a multi-line layout) ) ) )

  And it's not that much overhead anyway. From funcall to the actual
call you just get:
+ Binding of "Args"
+ Call to eval
+ Restoring of "Args"
which is as a bit less expensive than let plus one extra cell in the
prg, so it's about as costly as a let. Just that, no big deal.
-- 
UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe


Re: Ersatz update: Method references and functional interfaces

2013-03-17 Thread Alexander Burger
Hi Guillermo, Samuel,

I agree with all you both discussed, except for the 'funcall' issue.

> By the way, the current build of srborlongan-picolisp now includes
> java/funcall.l, 'cause you're awesome and your code is beautiful.


It is an important feature of PicoLisp that a construct like 'funcall'
is NOT needed.

One of the fundamental principles of the PicoLisp evaluation mechanisms
is that the CAR of a list is evaluated, and then used as a function.

Writing

   (de funcall "Args"
  (eval "Args") )

   (funcall (expression) 3 4)

is the same as

   (eval '((expression) 3 4))

instead of

   ((expression) 3 4)

and thus a tautology, just with a considerable overhead.


Moreover, if you publish code using 'funcall', new users will assume
this is the right way to do, and use it also in cases like

   (de foo (Fun)
  (funcall Fun 3 4) )

and

   (dm method> (Arg)
  (funcall (: hint) Arg) )

instead of simply

   (de foo (Fun)
  (Fun 3 4) )

and

   (dm method> (Arg)
  ((: hint) Arg) )

♪♫ Alex
-- 
UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe


patch to enable clang compilation of pil32 (on OSX)

2013-03-17 Thread Illo
Hello there!

Today, as a (likely useless) pet project, I've modified the C source code of 
pil32 so that it can be compiled with clang.

TD;LR: because clang refuses to implement a gcc extension[1], this patch 
plagues some (small) parts of the source code with macro calls, but compiled 
code works and is smaller than the one generated by gcc (on OSX, using the 
default ancient gcc and the latest clang).

This source concerned, the only two differences between gcc and clang are:
a) variable-sized arrays inside structures are not supported[1];
b) functions _appear_ to be aligned by default[2] (no formal proof about that, 
just evidence in disassemblies on both OSX and Linux).

Issue (b) being solved by definition, issue (a) remains. In pil32 source code, 
there are just a few spots where variable-sized arrays inside structures have 
been used, the pattern being (luckily) mostly the same: a bindFrame structure 
is defined inline with the internal array field "bnd" being set to a 
non-constant size. Its size is (sometimes) used to compute the number of 
elements to put into an index variable, and the current binding frame of the 
global environment is updated accordingly[3].

My solution has been to insert, near the definition of each bindFrame, a char 
array in the stack big enough to hold the whole bindFrame structure plus the 
variable size of 'bnd' inside (alloca() being unreliable). Then I've modified 
the in-place definitions of bindFrame so that bnd[...] would become bnd[0] 
(that is, a flexible array whose size isn't known at the end of a structure, as 
accepted by C99), and I've patched every access to sizeof(bnd) and access to 
bindFrame accordingly. This is an example:

--- before ---
/* ... */
struct {
   struct bindFrame *link;
   int i, cnt;
   struct {any sym; any val;} bnd[length(y)+2];
} f;
/* ... */ Env.bind = (bindFrame *)&f;
f.i = sizeof(f.bnd) / (2*sizeof(any)) - 1;
/* access to f. follow */

--- after ---
size_t _f_size = sizeof(any)*2*(length(y)+2);
struct {
   struct bindFrame *link;
   int i, cnt;
   struct {any sym; any val;} bnd[0];
} *f;
char _f_space[sizeof (*f) + _f_size];
f = (void*)_f_space;
/* ... */ Env.bind = (bindFrame *)f;
(*f).i = _f_space / (2*sizeof(any)) - 1;
/* access to (*f). follow */

-

Code changes have been performed so that the following goals could be reached:
- although the changes are compatible with gcc, I wanted the source to be the 
same as the original one when compiled with gcc, and produce the very same 
output;
- same performance;
- same stack usage (no heap allocations!);
- the source would have to be left mostly untouched[4] since I don't really 
know what it does (ahem);
- it should be possible to play with other (better) solutions.

With that in mind, I've coded four macros, awkwardly named.
- BNDFRAMEDEF(variable, non-const size) (e.g. using the previous example, 
BNDFRAMEDEF(f, length(y)+2))
  declares and defines a new bindFrame on the stack, assigned to (bindFrame *) 

- SIZEOFBND(variable) (e.g. SIZEOFBND(f))
  returns the size of the bnd array
- B(variable) (e.g. B(f).i = ...)
  used to access a field 
- BP(variable) (e.g. Env.bind = BP(f))
  used to access the bindFrame address on stack

These macros map to the new code when compiling with clang, and to the old code 
otherwise. Code follows:

---8><---8><---
#ifdef __clang__
#define INSTRUCT_VARLEN_ARRAYS_SUPPORT
#endif

#ifdef INSTRUCT_VARLEN_ARRAYS_SUPPORT
#warning "remapping in-struct verlength arrays"

#define BNDFRAMEDEF(v, s)\
size_t _##v##_size = sizeof(any)*2*(s);\
struct { \
struct bindFrame *link;\
int i, cnt;\
struct {any sym; any val;} bnd[0];\
} *v;\
char _##v##_space[sizeof(*v)+_##v##_size];\
v=(void *)_##v##_space
#define SIZEOFBND(v) _##v##_size
#define B(v) (*v)
#define BP(v) ((bindFrame*)v)

#else

#define BNDFRAMEDEF(v, s)\
struct {\
struct bindFrame *link;\
int i, cnt;\
struct {any sym; any val;} bnd[s];\
} v
#define SIZEOFBND(v) sizeof(v.bnd)
#define B(v) v
#define BP(v) ((bindFrame*)&v)

#endif /* INSTRUCT_VARLEN_ARRAYS_SUPPORT */
---8><---8><---

If somebody is interested in getting the whole patch, let me know. It's a 
Sunday morning divertissement (both trivial and useless since pil64 is 
(deservingly) the new hype). It's the fist time I take a serious look at 
picoLisp, and I hope some day to have the time to port pil64 on OSX -- although 
I hope /Mr.Burger/ will do it a lot sooner ;)

Ciao,
Illo.  

[1] 
http://clang.llvm.org/docs/UsersManual.html#intentionally-unsupported-gcc-extensions
[2] hence (maybe) the option "-falign-functions" being unsupported. It skips 
the option anyway so I left it in the Makefile.
[3] other parts of the code use the same pattern with constant sizes of 'bnd' 
and those haven't been modified.
[4] the be

Re: Ersatz update: Method references and functional interfaces

2013-03-17 Thread Guillermo R. Palavecino
On Sun, 17 Mar 2013 12:06:27 +0800
Samuel Dennis Borlongan  wrote:

> Thanks for the critique!
> 
> Pre-emptive apologies for the structure (or lack of it) of the reply
> below:
> 
> Apologies for making you refactor my sucky code.

  It was I who decided to refactor it so no worries.

> I wrote that at around 2 am because I wanted to post a (in
> retrospect, quite bad) example.

  And I replied that email at 5:30am ;-)
 
> Please note that I only use superparens in code that I need to type
> in the command line,

  I used to do that, but even in the commandline, I usually just put
parens, maybe it's a habit I picked writing code in emacs and
evaluating code from emacs itself (as well as interacting with the repl
for debugging) instead of using a commandline separately and (re)loading
files.

  (Just subtly throwing hints at you...)

> since unfortunately my build environment is a
> lot more awkward than you imagine:
> 
> I use Notepad++ and the default shell in Windows XP and above.

  Indeed, that's awkward.

> Apologies for the mapcars and code nesting. I've found that the best
> way to solve that problem in my "production" code is to refactor the
> nesting and mapcar-ing code into tiny easy-to-read functions (that do
> not depend on nesting and mapcar-ing). The beautiful thing about the
> Lisp family of languages is that refactoring (even via Notepad++) is
> significantly easier compared to other languages (though Java in
> Eclipse comes close, somewhat, maybe, probably, I don't know).

  You've got to try emacs + paredit (an advanced s-exp editor). Wish I
still had some old screencasts I made of what was my full emacs editor
stack for picolisp back then, but trust me, it's a life changer.

> P.S. Apologies for replying to this message in a delayed manner.

  No worries about that. Actually I don't usually reply emails right
away even if I have the time, unless it's an urgent matter. My
reasons are:
  1. I don't really like email.
  2. I like to distille what's going to be in an email (quality >
 speed/quantity)
  3. I don't care a lot about emails that:
a. Have little or nothing to do with me.
b. Treat topics I have_not_much_to_say/don't_care about.

> Personal issues (much more stressful than all the possible blunt
> critiques you can throw at me, and news on the state of the video
> game industry combined) prevented me from reading my mail.

  Oh? video game industry? Could you elaborate on that? if you don't
mind, that is...

  Last but not least, you should visit us sometimes at
#picol...@irc.freenode.net  ;-)

> On Fri, Mar 15, 2013 at 4:31 PM, Guillermo R. Palavecino
> wrote:
> 
> >   You should reconsider writing mapcars like crazy. Not only makes
> > the code overly redundant and verbose, but since picolisp has no
> > compiler, it will do exactly what you express, and so it will
> > traverse the list once for every mapcar you do, and what's worse,
> > it will create a new list each time (not to mention the resulting
> > list isn't used anywhere at all). Also, you are adding a lot of
> > unnecessary nesting by filling the ArrayList inside of the method.
> > All that code can be rewritten like this:
> >
> > (let ArrayList (ArrayList.new)
> >(for N (range 0 20)
> >   (funcall (.add> T ArrayList)
> >  (big:
> > (java
> >(funcall (.compareTo> T BigInteger.TEN)
> >   (big: N) ) ) ) ) )
> >(.forEach> (.stream> ArrayList)
> >   (Consumer.new
> >  (.println> T System.out) ) ) )
> >
> >   Personally I don't like the ((..) ..) nesting for function calls,
> > so I define a helper for these cases:
> >
> > (de funcall "Args"
> >(eval "Args") )
> >
> >   Learn to write with proper style before your codebase grows any
> > further or you'll have a lot to cleanup later. Readability matters.
> >
> >   Also, even though the superparens are nice and all, they don't
> > play well with most editors' paren matching, let alone advanced
> > s-exps editing tools. Instead of compulsively using them you can
> > try formatting your code better so you don't get that much nesting.
> > When someone is trying so hard to avoid parens, it usually means he
> > has not yet noticed that lisp parens are not nearly as abundant as
> > other symbols in common languages. Try to count the amount of
> > braces, parens, commas, infix operators, semicolon, etc you need in
> > java, then compare with lisp. Then ask yourself, are there really
> > so many parens? This is mostly a matter of getting used to lisp
> > syntax, but you never will if you don't try... and when you do,
> > maybe something will click inside you that will change for the
> > better the way you see lisp syntax... forever.
> >   I'm betting you are using some awkward editor to code picolisp.
> > Try emacs, with picolisp-mode, and paredit. It will change your
> > life.
> >
> >   Just my 2 cents. Hope you don't mind me being so blunt.
> >
> > On Wed, 13 Mar 2013 01:26:15 +0800
> > Samu