Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.forth > #49923 > unrolled thread

CfV: Quotations

Started byanton@mips.complang.tuwien.ac.at (Anton Ertl)
First post2016-08-10 16:52 +0000
Last post2016-09-03 06:47 +0000
Articles 20 on this page of 30 — 11 participants

Back to article view | Back to comp.lang.forth


Contents

  CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-10 16:52 +0000
    Re: CfV: Quotations Matthias Trute <matthias.trute@gmail.com> - 2016-08-10 11:19 -0700
    Re: CfV: Quotations Paul Rubin <no.email@nospam.invalid> - 2016-08-10 11:55 -0700
      Re: CfV: Quotations Bernd Paysan <bernd.paysan@gmx.de> - 2016-08-14 20:52 +0000
        Re: CfV: Quotations hughaguilar96@gmail.com - 2016-08-14 14:42 -0700
          Re: CfV: Quotations Julian Fondren <julian.fondren@gmail.com> - 2016-08-14 16:43 -0700
        Re: CfV: Quotations Paul Rubin <no.email@nospam.invalid> - 2016-08-15 22:16 -0700
          Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-16 07:13 +0000
            Re: CfV: Quotations Paul Rubin <no.email@nospam.invalid> - 2016-08-18 15:30 -0700
              Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-19 15:32 +0000
            Re: CfV: Quotations Bernd Paysan <bernd.paysan@gmx.de> - 2016-08-20 20:46 +0000
              Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-21 09:32 +0000
                Re: CfV: Quotations hughaguilar96@gmail.com - 2016-08-21 11:06 -0700
                  Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-24 17:02 +0000
                Re: CfV: Quotations Bernd Paysan <bernd.paysan@gmx.de> - 2016-08-21 22:52 +0000
                  Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-22 13:54 +0000
                    Re: CfV: Quotations Bernd Paysan <bernd.paysan@gmx.de> - 2016-08-22 23:19 +0000
                      Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-24 15:54 +0000
                        Re: CfV: Quotations Bernd Paysan <bernd@net2o.de> - 2016-08-28 00:43 +0000
                          Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-28 09:53 +0000
                            Re: CfV: Quotations Andrew Haley <andrew29@littlepinkcloud.invalid> - 2016-08-28 08:32 -0500
                              Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-28 14:38 +0000
    Re: CfV: Quotations mhx@iae.nl - 2016-08-10 12:02 -0700
    Re: CfV: Quotations Gerry Jackson <gerry@jackson9000.fsnet.co.uk> - 2016-08-11 17:25 +0100
    Re: CfV: Quotations Julian Fondren <julian.fondren@gmail.com> - 2016-08-11 12:48 -0700
    Re: CfV: Quotations minforth@arcor.de - 2016-08-16 03:31 -0700
    Re: CfV: Quotations Gerry Jackson <gerry@jackson9000.fsnet.co.uk> - 2016-08-31 15:15 +0100
      Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-08-31 15:26 +0000
        Re: CfV: Quotations Gerry Jackson <gerry@jackson9000.fsnet.co.uk> - 2016-09-02 22:33 +0100
          Re: CfV: Quotations anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2016-09-03 06:47 +0000

Page 1 of 2  [1] 2  Next page →


#49923 — CfV: Quotations

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2016-08-10 16:52 +0000
SubjectCfV: Quotations
Message-ID<2016Aug10.185227@mips.complang.tuwien.ac.at>
This is actually a poll about how widely the proposal is implemented
and how popular it is among the programmers.  It is called a CfV
(call-for-votes) because the process is inspired by the Usenet Rdf/CfV
process.

You find the actual ballot further down (look for "VOTING INSTRUCTIONS"),
after the proposal on which you vote.

Votetaker: Anton Ertl <anton@mips.complang.tuwien.ac.at>

Change history
--------------
28Jul2015 Alex McDonald v1 initial draft
04Aug2015 Alex McDonald v2 update
    added & extended "Rationale", "Discussion"
    formalised "Specification"
    corrected "Implementation"
    added "References"
01Jul2016 Anton Ertl v3
    various non-substantive changes throughout
    removed revised definition of RECURSE
    revised the stack effect to have quotation-sys colon-sys
    revised the specification wording
    added tests
28Jul2016 Anton Ertl v4
    ";" and ";CODE" in quotations are now ambiguous (v3 ToDo result)
    Added q6 test (please try it!)
    minor changes
10Aug2016 Anton Ertl CfV
    2 new tests, no other changes    

Quotations
==========

The essence of quotations is to provide nested colon definitions,
in which the inner definition(s) are nameless. The expression

: foo ... [: some words ;] ... ;

is equivalent to

:noname some words ; Constant #temp#
: foo ... #temp# ... ;

A simple quotation is an anonymous colon definition that is defined
inside a colon definition or quotation.

Rationale
---------

There is no situation where quotations cannot be implemented by
existing Forth words. Specifcially, :NONAME and : provide all the
features proposed for quotations. Their advantage is as a syntactic
"sugar" that permits a nameless definition in close proximity to its
use; and that it avoids generating one-use names only for the purpose
of refering to the definition inside another word.

One example use of quotations is to provide a solution to the use
of CATCH in a form close to other languages' TRY ... EXCEPT
blocks.

: hex. ( u -- )
  base @ >r
  [: hex u. ;] catch
  r> base ! throw ;

The advantage of using CATCH here is that the BASE is restored even if
there is an exception (e.g., a user interrupt) during the "U.".

Moreover, return-address manipulation has often been used as a way to
split a definition into several parts, e.g,:

: foo bar list> bla blub ;

where LIST> is a return-address manipulating word and executes the BLA
BLUB part of the word possibly several times.  This demonstrates that
introducing a helper definition is unattractive to these programmers;
with quotations this code could be written without helper word as

: foo bar [: bla blub ;] map-list ;

The advantages of this variant are: 1) Implementating quotations puts
less restrictions on the Forth system than implementing manipulable
return-addresses (which would restrict tail-call elimination and
inlining).  2) It is immediately visible to the reader that there is a
separate definition containing BLA BLUB.

Experience
----------

Under the term "Phrases", quotations have been in MacForth since at
least 1987. They are documented in the infamous "missing chapter" of
the MacForth manual.

Implementations exist in (at least) VFX, Gforth and iForth, and in the
iForth case appear to have some significant use and history.  The
Gforth development version from 2016-06-28 contains 70 occurences of
";]".

Interactions
------------

Quotations change the "current definition" that a number of words (in
particular, RECURSE, DOES> and locals) refer to, so we have to look at
the interactions of these words and locals.

In these interactions there is a conflict between interface simplicity
and implementation simplicity.  Disallowing all combinations of
quotations and these words would give most freedom to implementors to
choose the simplest implementation, but it would make for an interface
full of blind alleys: If you choose one feature, you cannot choose any
of the others; and if you need another feature, you have to back out
of using the first one.  Moreover, all these restrictions would have
to be specified in the standard.

This is not desirable, so here we propose to make all these words work
for quotations as well as they work for standalone definitions; this
is relatively cheap to implement.


RECURSE

RECURSE inside a quotation calls the quotation directly surrounding
the RECURSE, not the containing colon definition.

DOES>

A DOES> part inside a quotation ends with the terminating ";]"

Using DOES> is actually a useful example of using quotations.  E.g.,
<https://www.complang.tuwien.ac.at/forth/struct.fs> contains two
helper words (DOFIELD and DOZEROFIELD) in the following code:

  : dofield ( -- )
  does> ( name execution: addr1 -- addr2 )
      @ + ;
  
  : dozerofield ( -- )
      immediate
  does> ( name execution: -- )
      drop ;
  
  : field ( align1 offset1 align size "name" --  align2 offset2 )
      \ name execution: addr1 -- addr2
      2 pick >r \ this uglyness is just for optimizing with dozerofield
      create-field
      r> if \ offset<>0
        dofield
      else
        dozerofield
      then ;

Quotations allow to write this more compactly as:

  : field ( align1 offset1 align size "name" --  align2 offset2 )
      \ name execution: addr1 -- addr2
      2 pick >r \ this uglyness is just for optimizing with dozerofield
      create-field
      r> if \ offset<>0
        [: does> ( addr1 -- addr2 ) @ + ;]
      else
        immediate [: does> ( -- ) drop ;]
      then
      execute ;

The second RfD proposed to allow RECURSE after DOES> in general
(currently it is ambiguous), but this is not common practice yet, so
the present version removed this part of the proposal in order to
focus on the quotations proper.

Locals

A quotation may not be able to access the locals of the outer word
because it has no knowledge of when it might be executed and hence
whether outer locals are still alive. It does permit defining and
accessing its own locals.  Note that this means that both the
quotation and the containing definition may define locals.

: foo ... [: {: a b :} a b + ;] ... ; \ unambiguous
: bar {: a b :} ... [: a b + ;] ... ; \ ambiguous
: bla {: a ;} ... [: {: b ;} ... b ... ;] ... a ... ; \ unambiguous

The present proposal does not propose that a quotation can access the
locals of a containing definition, because the implementation would be
relatively complex, impose a run-time overhead, and the lifetime of
the locals would be restricted (unless we are willing to accept
further complexity).  While there are a number of people who are very
keen to have such a feature, it is not clear how much it would be
used.  System implementors are encouraged to provide support for
accessing outer locals on an experimental basis so that programmers
can explore the usefulness of this feature, possibly resulting in a
proposal for this feature in the future.


Syntax
------

The following notations have been seen in the wild, oldest first.
    :| ... |;
    :[ ... ]:
    [: ... ;]
    
The notation [: ;] appears to have popular support.


Specification
-------------

New system-compilation type quotation-sys with an
implementation-dependent size on the stack.  This type contains the
data that needs to be saved for the enclosing colon definition and
restored after the end of the quotation.  [Note: we use it in
combination with colon-sys, because DOES> uses colon-sys during
compilation.]

[:         bracket-colon
  Interpretation: Interpretation semantics for this word are undefined.

  Compilation: ( -- quotation-sys colon-sys )

  suspends compiling to the current definition, starts a new nested
  definition with execution token xt, and compilation continues with
  this nested definition. Locals may be defined in the nested
  definition.  An ambiguous condition exists if a name is used that
  satisfies the following constraints: 1) It is not the name of a
  currently visible local of the current quotation.  2) It is the name
  of a local that was visible right before the start of the present
  quotation or any of the containing quotations.

;]         semi-bracket
  Interpretation: Interpretation semantics for this word are undefined.

  Compilation: ( c: quotation-sys colon-sys -- )

  Ends the current nested definition, and resumes compilation to the
  previous (containing) current definition. It appends the following
  run-time to the (containing) current definition:

  run-time: ( -- xt )

  xt is the execution token of the nested definition.

Add the following ambiguous condition to ";" and ";CODE":

An ambiguous condition exists if the compilation semantics of ";" or
";CODE" are performed inside a quotation.


Implementation
--------------

It is not possible to define quotations in ISO Forth. The following
is an outline definition, where SAVE-DEFINITION-STATE and RESTORE-
DEFINITION-STATE require carnal knowledge of the system and are left
to the implementor.

: [: ( c: -- quotation-sys colon-sys )
  postpone ahead save-definition-state :noname ; immediate
: ;] ( c: quotation-sys colon-sys -- ) ( s: -- xt )
  postpone ; >r restore-definition-state
  postpone then r> postpone literal ; immediate


Compliance Tests
----------------

\ works on Gforth:

T{ : q1 [: 1 ;] ;  q1 execute -> 1 }T
T{ : q2 [: [: 2 ;] ;] ;  q2 execute execute -> 2 }T
T{ : q3 {: a :} [: {: a b :} b a ;] ;  1 2 3 q3 execute -> 2 1 }T
T{ : q4 [: dup if dup 1- recurse then ;] ;  3 q4 execute .s -> 3 2 1 0 }T
T{ : q5 [: does> drop 4 ;] 5 swap ;  create x  q5 execute x -> 5 4 }T
T{ : q6 {: a :} [: {: a b :} b a ;] a 1+ ;  1 2 q6 swap execute -> 3 1 }T
T{ 1 2 q6 q6 swap execute execute -> 4 1 }T
T{ 1 2 3 q3 swap q6 swap execute  execute -> 3 1 }T

References
----------

Stephen Pelc wrote this; see

http://newsgroups.derkeiler.com/Archive/Comp/comp.lang.forth/2012-07/msg00791.html

I (Alex McDonald) have taken it and modified it as a proposed RfD,
and have removed the discussion of closures. http://www.forth200x.org/

I (Anton Ertl) have taken it and revised it.

The following notes on quotations and closures incorporate material
from several people, including Anton Ertl, Andrew Haley, Marcel
Hendrix, Ward Mcfarland, Bernd Paysan, and Elizabeth Rather. If you
have been left out and want acknowledgement, please let me know.

Additional contributors: Gerry Jackson and others.

[Note]
The phrase "ambiguous condition" has a specific meaning in Forth
standards. An ambiguous condition is "a circumstance for which this
standard does not prescribe a specific behavior". The RfD process
also states: "If you want to leave something open to the system
implementor, make that explicit, e.g., by making it an ambiguous
condition."



VOTING INSTRUCTIONS

Fill out the appropriate ballot(s) below and mail it/them to the
votetaker <anton@mips.complang.tuwien.ac.at>.  Your vote will be
published (including your name (without email address) and/or the name
of your system) here.  You can vote (or change your vote) at any time
by mailing to me, and the results will be published here.

Note that you can be both a system implementor and a programmer, so
you can submit both kinds of ballots.

Ballot for systems

If you maintain several systems, please mention the systems separately
in the ballot.  Insert the system name or version between the brackets
or in the line below the statement.  Multiple hits for the same system
are possible (if they do not conflict).

[ ] conforms to ANS Forth.
[ ] already implements the proposal in full since release [ ].
[ ] implements the proposal in full in a development version.
[ ] will implement the proposal in full in release [ ].
[ ] will implement the proposal in full in some future release.
[ ] There are no plans to implement the proposal in full in [ ].
[ ] will never implement the proposal in full.

If you want to provide information on partial implementation, please do
so informally, and I will aggregate this information in some way.


Ballot for programmers

Just mark the statements that are correct for you (e.g., by putting
your name on the line below the statement you agree with).  If some
statements are true for some of your programs, but not others, please
mark the statements for the dominating class of programs you write.

[ ] I have used (parts of) this proposal in my programs.
[ ] I would use (parts of) this proposal in my programs if the systems
     I am interested in implemented it.
[ ] I would use (parts of) this proposal in my programs if this
     proposal was in the Forth standard.
[ ] I would not use (parts of) this proposal in my programs.

If you feel that there is closely related functionality missing from the
proposal (especially if you have used that in your programs), make an
informal comment, and I will collect these, too. Note that the best time
to voice such issues is the RfD stage.

-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2016: http://www.euroforth.org/ef16/

[toc] | [next] | [standalone]


#49927

FromMatthias Trute <matthias.trute@gmail.com>
Date2016-08-10 11:19 -0700
Message-ID<73dacc62-7270-428c-9c8b-1517c7626301@googlegroups.com>
In reply to#49923
Vote for amforth and me

> Ballot for systems
> 
> [ ] conforms to ANS Forth.
> [X] already implements the proposal in full since release [5.1].
> [ ] implements the proposal in full in a development version.
> [ ] will implement the proposal in full in release [ ].
> [ ] will implement the proposal in full in some future release.
> [ ] There are no plans to implement the proposal in full in [ ].
> [ ] will never implement the proposal in full.
> 
> Ballot for programmers
> 
> [X] I have used (parts of) this proposal in my programs.
> [X] I would use (parts of) this proposal in my programs if the systems
>      I am interested in implemented it.
> [ ] I would use (parts of) this proposal in my programs if this
>      proposal was in the Forth standard.
> [ ] I would not use (parts of) this proposal in my programs.
> 

Matthias

[toc] | [prev] | [next] | [standalone]


#49930

FromPaul Rubin <no.email@nospam.invalid>
Date2016-08-10 11:55 -0700
Message-ID<87lh041mjx.fsf@jester.gateway.pace.com>
In reply to#49923
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
> Ballot for programmers
> [ ] I have used (parts of) this proposal in my programs.
> [X] I would use (parts of) this proposal in my programs if the systems
>      I am interested in implemented it.
> [X] I would use (parts of) this proposal in my programs if this
>      proposal was in the Forth standard.
> [ ] I would not use (parts of) this proposal in my programs.

I might post some comments later.  Basically as currently proposed it's
more of a minor convenience feature than something that makes Forth
really feel more capable.  If they were there I'd use them but I
can do without them.

I'm sympathetic to the calls for quotations to be able to access (at
least for reading) the parent locals, like C++ lambdas (C++'s version of
quotations) can do.  I don't think comparisons with Lisp or Scheme are
that useful, but comparisons to C++ might be worthwhile.

The C++ server framework http://www.seastar-project.org/ relies on
lambdas, often nested several levels deep and sometimes using
assignments inside the lambda list, a new feature of C++14.

C++ lambdas like everything else in C++ have a lot of complicated,
interacting features, but all those features address actual use cases
and were deemed worthy of support.  They were introduced in C++11 and
enhanced slightly in C++14 and again in C++17 as new uses have appeared,
showing it can take multiple iterations to get something like this
right.  I use them regularly in my own C++ code, and someday I want to
try using Seastar (linked above), which relies on them heavily.

[toc] | [prev] | [next] | [standalone]


#50096

FromBernd Paysan <bernd.paysan@gmx.de>
Date2016-08-14 20:52 +0000
Message-ID<noqlm8$ag1$3@dont-email.me>
In reply to#49930
Am Wed, 10 Aug 2016 11:55:14 -0700 schrieb Paul Rubin:
> I'm sympathetic to the calls for quotations to be able to access (at
> least for reading) the parent locals, like C++ lambdas (C++'s version of
> quotations) can do.  I don't think comparisons with Lisp or Scheme are
> that useful, but comparisons to C++ might be worthwhile.

C/C++ has no stack the lambda would be able to access. E.g. if you want 
to count words in a wordlist with TRAVERSE-WORDLIST and quotations, you do

: count-wl ( wid -- count )
  >r 0 [: ( n nt -- n' flag ) drop 1+ true ;] r> traverse-wordlist ; 

Now do that in C++, and you need to access an outer local for that.  You 
don't even have a chance to do it that way, because you can't extend the 
stack effect ( nt -- flag ) in a C++ function.  In Forth, you can, and 
iterators can be written so that they keep their internal state off the 
data stack when calling the xt passed to them.

Forth is not a locals-centric language, it's a stack-centric language.  
You can use the stack to pass data through quotations used e.g. as 
iterators.

Without the stack, quotations would be much less useful.

The problem with nested functions is not only that they are more 
difficult to implement, it's also that they can't outlive their parent's 
stack frame lifetime, and quotations which do are part of the use cases.

This has been discussed to death already, with Hugh shouting at me for my 
"fake quotations".  They are Forth quotations, not Lisp or C++ lambdas, 
because in Forth, we have stacks.  And locals are an optional feature.

-- 
Bernd Paysan
"If you want it done right, you have to do it yourself"
net2o ID: kQusJzA;7*?t=uy@X}1GWr!+0qqp_Cn176t4(dQ*
http://bernd-paysan.de/

[toc] | [prev] | [next] | [standalone]


#50105

Fromhughaguilar96@gmail.com
Date2016-08-14 14:42 -0700
Message-ID<903ddcc1-59cf-4088-afc2-8732fad021ca@googlegroups.com>
In reply to#50096
On Sunday, August 14, 2016 at 1:52:25 PM UTC-7, Bernd Paysan wrote:
> Am Wed, 10 Aug 2016 11:55:14 -0700 schrieb Paul Rubin:
> > I'm sympathetic to the calls for quotations to be able to access (at
> > least for reading) the parent locals, like C++ lambdas (C++'s version of
> > quotations) can do.  I don't think comparisons with Lisp or Scheme are
> > that useful, but comparisons to C++ might be worthwhile.
> 
> C/C++ has no stack the lambda would be able to access. E.g. if you want 
> to count words in a wordlist with TRAVERSE-WORDLIST and quotations, you do
> 
> : count-wl ( wid -- count )
>   >r 0 [: ( n nt -- n' flag ) drop 1+ true ;] r> traverse-wordlist ; 
> 
> Now do that in C++, and you need to access an outer local for that.  You 
> don't even have a chance to do it that way, because you can't extend the 
> stack effect ( nt -- flag ) in a C++ function.  In Forth, you can, and 
> iterators can be written so that they keep their internal state off the 
> data stack when calling the xt passed to them.
> 
> Forth is not a locals-centric language, it's a stack-centric language.  
> You can use the stack to pass data through quotations used e.g. as 
> iterators.
> 
> Without the stack, quotations would be much less useful.
> 
> The problem with nested functions is not only that they are more 
> difficult to implement, it's also that they can't outlive their parent's 
> stack frame lifetime, and quotations which do are part of the use cases.
> 
> This has been discussed to death already, with Hugh shouting at me for my 
> "fake quotations".  They are Forth quotations, not Lisp or C++ lambdas, 
> because in Forth, we have stacks.  And locals are an optional feature.

With the Paysan-faked quotations, locals are not an "optional feature" --- you don't provide any way for the quotation to access the parent function's locals, so locals are not an option at all --- by comparison, with my rquotations the user can either communicate via the data-stack or via locals.

Consider this code in which the rquotation communicates with the parent function via locals:
-----------------------------------------------------------------------------
seq 
    w field .gender     \ 'M' or 'F'     \ if someone isn't one or the other, then he/she isn't a person 
constant person 

: init-person ( str node -- node ) 
    init-seq >r 
    [char] M  r@ .gender !    \ default is male 
    r> ; 
    
: new-person ( str -- node )     
    person alloc 
    init-person ; 

person 
    w field .hotness    \ scale of 1 to 10 
constant chick 

: init-chick ( hotness str node -- node ) 
    init-person >r 
    [char] F  r@ .gender ! 
              r@ .hotness ! 
    r> ; 
    
: new-chick ( hotness str -- node )     
    chick alloc 
    init-chick ; 

: test { head | people chicks tens nines eights -- } 
    head r[ 
        1 +to people 
        dup .gender @  [char] F = if  1 +to chicks 
            .hotness @ 
            dup  8 = if  1 +to eights  then 
            dup  9 = if  1 +to nines  then 
            10 = if  1 +to tens  then        \ Yay! We found at least one! 
        else  drop  then 
    ]r |each 
    cr ." total people:    " people . 
    cr ." total chicks:    " chicks . 
    cr ." level 10 chicks: " tens . 
    cr ." level  9 chicks: " nines . 
    cr ." level  8 chicks: " eights . 
    ; 
-----------------------------------------------------------------------------

Here is a test:
-----------------------------------------------------------------------------
people show-seq 
aaaaa
bbbbb
ccccc
Darby
eeeee
fffff
ggggg
hhhhh
 ok
people test 
total people:    8 
total chicks:    5 
level 10 chicks: 1 
level  9 chicks: 0 
level  8 chicks: 2  ok
-----------------------------------------------------------------------------

Now here is a light-weight function in which we don't use locals but rather just communicate via the data-stack (because this time we only have one counter that we are updating):
-----------------------------------------------------------------------------
: chick-counter ( head -- chicks ) 
    0
    swap  r[ .gender @  [char] F = if  1+  then  ]r |each ;
-----------------------------------------------------------------------------

Here is a test:
-----------------------------------------------------------------------------
people chick-counter  ok-1 
. 5  ok
-----------------------------------------------------------------------------

So, my rquotations are robust --- the user has the option of either communicating with the parent function via locals or via the data-stack --- by comparison, you force the user to always communicate via the data-stack, even when there are several data that need to be communicated (in my first example, the several counters).

All in all, I think that I'm way ahead of Forth-200x --- you aren't even close to having the capability that I have in the novice-package --- this wouldn't bother me, except for the fact that you insist on declaring everything that you do to be the Standard, effectively holding down the entire Forth community to your own level of incompetence.

BTW: I have noticed that every time the subject of quotations and HOFs comes up, you always trot out TRAVERSE-WORDLIST as your example HOF --- I get the impression that TRAVERSE-WORDLIST is the only HOF that you have ever written.

[toc] | [prev] | [next] | [standalone]


#50110

FromJulian Fondren <julian.fondren@gmail.com>
Date2016-08-14 16:43 -0700
Message-ID<6d1603cc-8f2d-4c5b-8081-9604de8b5b06@googlegroups.com>
In reply to#50105
On Sunday, August 14, 2016 at 4:42:13 PM UTC-5, hughag...@gmail.com wrote:
> With the Paysan-faked quotations, locals are not an "optional feature" --- 

Locals are defined in the "The optional Locals word set" of ANS
Forth.  They are an "optional feature" to Forth.

> 
> BTW: I have noticed that every time the subject of quotations and HOFs comes up, you always trot out TRAVERSE-WORDLIST as your example HOF --- I get the impression that TRAVERSE-WORDLIST is the only HOF that you have ever written.

I can't read this as anything but a request for clf to tell you if
you've worn out your one example and need to come up with another.

[toc] | [prev] | [next] | [standalone]


#50164

FromPaul Rubin <no.email@nospam.invalid>
Date2016-08-15 22:16 -0700
Message-ID<87lgzxuwdr.fsf@jester.gateway.pace.com>
In reply to#50096
Bernd Paysan <bernd.paysan@gmx.de> writes:
> : count-wl ( wid -- count )
>   >r 0 [: ( n nt -- n' flag ) drop 1+ true ;] r> traverse-wordlist ; 
> Now do that in C++, and you need to access an outer local for that.

That would be a pretty unnatural interface for traverse-wordlist in C++,
but I see what you mean.  It effectively uses the stack as a shared
global.  I guess that's ok in this setting.  In C++ traverse-wordlist
would probably return an iterator and you'd loop over it or use std::count.

> Forth is not a locals-centric language, it's a stack-centric
> language...  Without the stack, quotations would be much less useful.

Locals are optional but I'd hope quotations are even more optional?

> The problem with nested functions is not only that they are more 
> difficult to implement, it's also that they can't outlive their parent's 
> stack frame lifetime, and quotations which do are part of the use cases.

I wonder how often quotations will leave stuff on the stack for use by
the next iteration of something.  I'm used to using a HOF like "fold" or
"reduce" for that, though it would seem weird in Forth.

If you don't need any mutable global state (like the stack) then you can
pass parameters into the lambda, which can survive the parent returning.

[toc] | [prev] | [next] | [standalone]


#50168

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2016-08-16 07:13 +0000
Message-ID<2016Aug16.091357@mips.complang.tuwien.ac.at>
In reply to#50164
Paul Rubin <no.email@nospam.invalid> writes:
>Bernd Paysan <bernd.paysan@gmx.de> writes:
>> Forth is not a locals-centric language, it's a stack-centric
>> language...  Without the stack, quotations would be much less useful.
>
>Locals are optional but I'd hope quotations are even more optional?

I expect quotations to become CORE EXT, so there would be no
requirement to implement locals in order to implement quotations.
There is also no reason to, given that quotations cannot access outer
locals in the proposed quotations.

>> The problem with nested functions is not only that they are more 
>> difficult to implement, it's also that they can't outlive their parent's 
>> stack frame lifetime, and quotations which do are part of the use cases.
>
>I wonder how often quotations will leave stuff on the stack for use by
>the next iteration of something.  I'm used to using a HOF like "fold" or
>"reduce" for that, though it would seem weird in Forth.

Depending on the HOF, but I expect it to happen pretty often for those
that call the xt multiple times.  In Forth, you can use the same HOF
for foreach and for reduce.

>If you don't need any mutable global state (like the stack) then you can
>pass parameters into the lambda, which can survive the parent returning.

You can pass parameters through the stacks in addition to keeping
computed values on the stack.  Of course, if there are too many,
things become unwieldy.  E.g. (untested):

: fmap ( ... addr u xt -- ... )
\ addr u is a floating-point array with u elements starting at addr.
\ call xt ( ... r -- ... ) once for each element r
  ... ;

2e 0e v vlen [: ( rexp racc r -- rexp racc1 ) 2 fpick f** f+ :] fmap

Bernd Paysan thinks that's good enough.  I am not sure.  Especially
when working with several HOFs at once, it becomes hard to follow what
happens on the stack.  Or maybe it's just that we are not used to
dealing with that.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2016: http://www.euroforth.org/ef16/

[toc] | [prev] | [next] | [standalone]


#50224

FromPaul Rubin <no.email@nospam.invalid>
Date2016-08-18 15:30 -0700
Message-ID<874m6hvhfc.fsf@jester.gateway.pace.com>
In reply to#50168
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
> I expect quotations to become CORE EXT

Hmm, that surprises me a bit, since quotations seem like an esoteric
feature for most Forth users.  But I guess the implementation can be
very simple..  

> so there would be no requirement to implement locals in order to
> implement quotations.

IMO locals are much more useful, so regardless of implementation
dependencies, if I had to pick just one I'd pick locals.

> 2e 0e v vlen [: ( rexp racc r -- rexp racc1 ) 2 fpick f** f+ :] fmap

> Bernd Paysan thinks that's good enough.  I am not sure.  Especially
> when working with several HOFs at once, it becomes hard to follow what
> happens on the stack.  Or maybe it's just that we are not used to
> dealing with that.

That example is readable but yes, it does get worse with deeper levels
of HOF.  Witness Haskell vs Python: the languages have similar raw
capabilities, but Haskell uses HOFs more freely because its type system
keeps them from getting out of control.

I think that Forthers generally don't want to use so much abstraction so
maybe it won't be an issue.  In fact I wonder if we language geeks are
irresistably drawn to features that working practitioners (hardware
designers etc.) don't particularly care about.  The whole quotation
discussion could be an example of that.

[toc] | [prev] | [next] | [standalone]


#50252

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2016-08-19 15:32 +0000
Message-ID<2016Aug19.173224@mips.complang.tuwien.ac.at>
In reply to#50224
Paul Rubin <no.email@nospam.invalid> writes:
>anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
>> I expect quotations to become CORE EXT
>
>Hmm, that surprises me a bit, since quotations seem like an esoteric
>feature for most Forth users.

CORE EXT is the typical place for things that do not belong anywhere
else.  Another place might be TOOLS EXT, but looking at 15.1 and
15.6.1, I don't think that's the right place (but the same could be
said of a number of things in TOOLS EXT; e.g., AHEAD, CODE, ;CODE
etc. are not just used during development, but also in the finished
applications.

Anyway, if we put it in TOOLS EXT, you can still have a standard
system with quotations and without locals.

>> 2e 0e v vlen [: ( rexp racc r -- rexp racc1 ) 2 fpick f** f+ :] fmap
>
>> Bernd Paysan thinks that's good enough.  I am not sure.  Especially
>> when working with several HOFs at once, it becomes hard to follow what
>> happens on the stack.  Or maybe it's just that we are not used to
>> dealing with that.
>
>That example is readable but yes, it does get worse with deeper levels
>of HOF.  Witness Haskell vs Python: the languages have similar raw
>capabilities, but Haskell uses HOFs more freely because its type system
>keeps them from getting out of control.

I think that the tendency of Haskell to use currying (coming from the
syntax) plays a bigger role, as well as the culture of functional
programming.

>I think that Forthers generally don't want to use so much abstraction so
>maybe it won't be an issue.  In fact I wonder if we language geeks are
>irresistably drawn to features that working practitioners (hardware
>designers etc.) don't particularly care about.  The whole quotation
>discussion could be an example of that.

Certainly, looking at the current CfV results, there seem to be a
bunch of people who have already used quotations, and a bunch of
people who say they will never use quotations.  I have worked around
their absence (by defining helper words) for decades, other people
have worked around their absence with return-address maniupulations,
so I don't think that practitioners don't care about them, unless you
define a practitioner to be someone who does not care about
quotations.

Looking at other languages, closures have been limited to functional
languages for a long time, but a few years ago, "lambdas" started
appearing in C#, then in Java and C++.  I guess there's a contingent
of programmers in these languages who don't need lambdas and won't use
it, but others use lambdas; it's probably too early to tell the
overall effect of lambda on these languages.

An earlier innovation was genericity; at the start this was probably
also something only for language geeks, but I think it's now
mainstream in Java, C++, and C#.  Just if anybody wonders if we need
this in Forth: Genericity is a solution for a problem that these
languages get from their static typechecking; Forth has no
typechecking, so it does not need to add genericity to the type
system.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2016: http://www.euroforth.org/ef16/

[toc] | [prev] | [next] | [standalone]


#50295

FromBernd Paysan <bernd.paysan@gmx.de>
Date2016-08-20 20:46 +0000
Message-ID<npafji$59r$1@dont-email.me>
In reply to#50168
Am Tue, 16 Aug 2016 07:13:57 +0000 schrieb Anton Ertl:
> : fmap ( ... addr u xt -- ... )
> \ addr u is a floating-point array with u elements starting at addr. \
> call xt ( ... r -- ... ) once for each element r
>   ... ;
> 
> 2e 0e v vlen [: ( rexp racc r -- rexp racc1 ) 2 fpick f** f+ :] fmap
> 
> Bernd Paysan thinks that's good enough.  I am not sure.  Especially when
> working with several HOFs at once, it becomes hard to follow what
> happens on the stack.  Or maybe it's just that we are not used to
> dealing with that.

As usual in Forth, you shouldn't deal with "too many variables" (see 
Thinking Forth page 210 in the online edition), nor should you write a 
word with HOFs inside HOFs inside HOFs.

If you really need a complex data structure, use and OOP package, best 
one with a current object, because that current object will be current 
inside the quotation, too, without any stack juggling.

-- 
Bernd Paysan
"If you want it done right, you have to do it yourself"
net2o ID: kQusJzA;7*?t=uy@X}1GWr!+0qqp_Cn176t4(dQ*
http://bernd-paysan.de/

[toc] | [prev] | [next] | [standalone]


#50326

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2016-08-21 09:32 +0000
Message-ID<2016Aug21.113258@mips.complang.tuwien.ac.at>
In reply to#50295
Bernd Paysan <bernd.paysan@gmx.de> writes:
>Am Tue, 16 Aug 2016 07:13:57 +0000 schrieb Anton Ertl:
>> Bernd Paysan thinks that's good enough.  I am not sure.  Especially when
>> working with several HOFs at once, it becomes hard to follow what
>> happens on the stack.  Or maybe it's just that we are not used to
>> dealing with that.
>
>As usual in Forth, you shouldn't deal with "too many variables" (see 
>Thinking Forth page 210 in the online edition),

This talks about global variables, and says nothing about "too many
variables".  Maybe you mean the cartoon on Page 209, but that does not
present a solution to the problem.

>nor should you write a 
>word with HOFs inside HOFs inside HOFs.

HOFs inside HOFs are easy.  There is only one HOF to consider at each
point in this case.  It's harder if you pass HOFs to HOFs.

Anyway, if a Forther gives me "you should not"s without a supporting
argument, nor presenting an alternative approach, it's an indication
that there is some lack in the language.  So maybe keeping the
not-quite-local data on the data stack is not enough to make accesses
to outer locals unnecessary.

>If you really need a complex data structure, use and OOP package, best 
>one with a current object, because that current object will be current 
>inside the quotation, too, without any stack juggling.

Ok, so your solution is to have one global variable, and access all
the other data through that.  I very much doubt that is sufficient,
because global variables are not sufficient to implement nested
Pascal's and GNU C's nested functions, either; instead, they do static
link chains and trampolines.  E.g, I don't think you can do the
man-or-boy-test with that.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2016: http://www.euroforth.org/ef16/

[toc] | [prev] | [next] | [standalone]


#50334

Fromhughaguilar96@gmail.com
Date2016-08-21 11:06 -0700
Message-ID<b2548da8-fc99-46d1-8323-f32dcb3e336f@googlegroups.com>
In reply to#50326
On Sunday, August 21, 2016 at 2:57:30 AM UTC-7, Anton Ertl wrote:
> Bernd Paysan <bernd.paysan@gmx.de> writes:
> >nor should you write a 
> >word with HOFs inside HOFs inside HOFs.
> 
> HOFs inside HOFs are easy.  There is only one HOF to consider at each
> point in this case.  It's harder if you pass HOFs to HOFs.

The phrase "HOFs inside HOFs" makes no sense --- you can have quotations inside of functions, but HOFs are named functions which are not inside of other functions --- I've noticed before that you guys' terminology is mixed up; you seem to not know the difference between a HOF and a quotation.

These are my rules for rquotations:
1.) The rquotation must be called with REX rather than EXECUTE. 
2.) Only a HOF can use REX. 
3.) A HOF can not call another HOF. 
4.) A HOF must have local variables. 

If you do this, then the rquotation can access the parent function's local variables.

These are easy rules to follow because this is the way that you would want to use quotations almost all of the time anyway.

[toc] | [prev] | [next] | [standalone]


#50450

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2016-08-24 17:02 +0000
Message-ID<2016Aug24.190223@mips.complang.tuwien.ac.at>
In reply to#50334
hughaguilar96@gmail.com writes:
>On Sunday, August 21, 2016 at 2:57:30 AM UTC-7, Anton Ertl wrote:
>> Bernd Paysan <bernd.paysan@gmx.de> writes:
>> >nor should you write a=20
>> >word with HOFs inside HOFs inside HOFs.
>>=20
>> HOFs inside HOFs are easy.  There is only one HOF to consider at each
>> point in this case.  It's harder if you pass HOFs to HOFs.
>
>The phrase "HOFs inside HOFs" makes no sense

What I meant is a call of a higher-order word inside a higher-order
word.  A typical example is

: with-base ( n xt -- )
  base @ >r
  [: swap base ! execute ;] catch
  r> base ! throw ;

12345 $10 ' . with-base

WITH-BASE takes and xt and is therefore a higher-order word, and so is
CATCH.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2016: http://www.euroforth.org/ef16/

[toc] | [prev] | [next] | [standalone]


#50365

FromBernd Paysan <bernd.paysan@gmx.de>
Date2016-08-21 22:52 +0000
Message-ID<npdbbl$vqt$2@dont-email.me>
In reply to#50326
Am Sun, 21 Aug 2016 09:32:58 +0000 schrieb Anton Ertl:

> Ok, so your solution is to have one global variable, and access all the
> other data through that.  I very much doubt that is sufficient, because
> global variables are not sufficient to implement nested Pascal's and GNU
> C's nested functions, either; instead, they do static link chains and
> trampolines.  E.g, I don't think you can do the man-or-boy-test with
> that.

Well, the boy-or-man test isn't really needing better quotations, it's 
needing a bit more OOP.  It wants something applied in a "context", and 
we call that "method".  While you could have many methods, here, one is 
sufficient.  While you could have many different object lifetime schemes, 
stack-allocated here is sufficient.

require mini-oof2.fs

\ define a class for the default values

object class
    field: k
    method b
end-class mob

:noname ( -- n ) k @ ; mob to b
mob new constant m-1  -1 m-1 .k !
mob new constant m0    0 m0 .k !
mob new constant m1    1 m1 .k !

\ define a class for the context

mob class
    field: x1
    field: x2
    field: x3
    field: x4
    field: x5
end-class b-ctx

: a ( k x1 x2 x3 x4 x5 -- result )
    b-ctx new >o
    x5 ! x4 ! x3 ! x2 ! x1 ! k !
    k @ 0<= IF
	x4 @ .b x5 @ .b +
    ELSE
	b
    THEN
    dispose o> ;

:noname ( -- n )
    -1 k +!
    k @ o x1 @ x2 @ x3 @ x4 @ a
; b-ctx to b

: a-n ( n -- n' )
    m1 m-1 m-1 m1 m0 a ;

Test with a bit more return stack space than usual (I just set it to 1G):

27 0 [do] cr [i] dup . a-n . [lOOP]  
0 1 
1 0 
2 -2 
3 0 
4 1 
5 0 
6 1 
7 -1 
8 -10 
9 -30 
10 -67 
11 -138 
12 -291 
13 -642 
14 -1446 
15 -3250 
16 -7244 
17 -16065 
18 -35601 
19 -78985 
20 -175416
21 -389695 
22 -865609 
23 -1922362 
24 -4268854 
25 -9479595 
26 -21051458  ok

Looks good.  If you want OOP, use OOP.  If you want something that is 
slightly less than OOP, just use OOP, too, please.  Unlike nested 
functions, OOP is dead easy to implement.  It really is powerful enough, 
way more powerful than nested functions, as powerful as closures.  As 
quotations are mostly syntactic sugar, they are not needed at all here.

Maybe you want an object on the locals stack to get rid of the relatively 
expensive new/dispose pairs.

-- 
Bernd Paysan
"If you want it done right, you have to do it yourself"
net2o ID: kQusJzA;7*?t=uy@X}1GWr!+0qqp_Cn176t4(dQ*
http://bernd-paysan.de/

[toc] | [prev] | [next] | [standalone]


#50406

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2016-08-22 13:54 +0000
Message-ID<2016Aug22.155432@mips.complang.tuwien.ac.at>
In reply to#50365
Bernd Paysan <bernd.paysan@gmx.de> writes:
>Am Sun, 21 Aug 2016 09:32:58 +0000 schrieb Anton Ertl:
>
>> Ok, so your solution is to have one global variable, and access all the
>> other data through that.  I very much doubt that is sufficient, because
>> global variables are not sufficient to implement nested Pascal's and GNU
>> C's nested functions, either; instead, they do static link chains and
>> trampolines.  E.g, I don't think you can do the man-or-boy-test with
>> that.
>
>Well, the boy-or-man test isn't really needing better quotations, it's 
>needing a bit more OOP.

Sure, you can implement the functionality in some way in any
Touring-complete language.  But the original test was for whether
nested functions in Algol 60 were correctly implemented.  So if it can
be implemented with closures (actually Pascal function parameters are
sufficient), but not with the proposed quotations, it shows that
passing data on the stack does not replace non-local data accesses in
every case.  Of course, as is often the case in Forth, the question is
if the various approaches for avoiding a feature are sufficient to
make that feature unnecessary or not.

>require mini-oof2.fs
>
>\ define a class for the default values
>
>object class
>    field: k
>    method b
>end-class mob
>
>:noname ( -- n ) k @ ; mob to b
>mob new constant m-1  -1 m-1 .k !
>mob new constant m0    0 m0 .k !
>mob new constant m1    1 m1 .k !
>
>\ define a class for the context
>
>mob class
>    field: x1
>    field: x2
>    field: x3
>    field: x4
>    field: x5
>end-class b-ctx
>
>: a ( k x1 x2 x3 x4 x5 -- result )
>    b-ctx new >o
>    x5 ! x4 ! x3 ! x2 ! x1 ! k !
>    k @ 0<= IF
>	x4 @ .b x5 @ .b +
>    ELSE
>	b
>    THEN
>    dispose o> ;
>
>:noname ( -- n )
>    -1 k +!
>    k @ o x1 @ x2 @ x3 @ x4 @ a
>; b-ctx to b
>
>: a-n ( n -- n' )
>    m1 m-1 m-1 m1 m0 a ;

For comparsion, here's the Algol 60 variant:

begin
  real procedure A(k, x1, x2, x3, x4, x5);
  value k; integer k;
  begin
    real procedure B;
    begin k := k - 1;
          B := A := A(k, B, x1, x2, x3, x4);
    end;
    if k <= 0 then A := x4 + x5 else B;
  end;
  outreal(A(10, 1, -1, -1, 1, 0));
end;

and my attempt at a version in Forth with access to outer locals,
based on <http://rosettacode.org/wiki/Man_or_boy_test#Pascal> (my
Algol 60 is not good enough to grasp the fine details of the Algol 60
version):

0 constant zero
1 constant one
-1 constant negone

: A {: k x1 x2 x3 x4 x5 | B -- n :} recursive
  [: k 1- to k
     k B x1 x2 x3 x4 A ;] to B
  k 0 <= if
    x4 execute x5 execute +
  else
    B execute
  then ;

10 ' one ' negone ' negone ' one ' zero A .

So access to outer locals makes this quite a bit shorter (14 instead
of 41 lines) than making the frames explicit by coding them in OOP.

The question is how often that helps for real-world programs.  My
guess is that, with the Pascal-like restriction, not often enough to
make it worthwhile.  With garbage-collection of closures, it would
probably be worthwhile, but we probably don't want to go there; and
for something in between, we will have to see.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2016: http://www.euroforth.org/ef16/

[toc] | [prev] | [next] | [standalone]


#50412

FromBernd Paysan <bernd.paysan@gmx.de>
Date2016-08-22 23:19 +0000
Message-ID<npg1ao$29b$1@dont-email.me>
In reply to#50406
Am Mon, 22 Aug 2016 13:54:32 +0000 schrieb Anton Ertl:
> The question is how often that helps for real-world programs.  My guess
> is that, with the Pascal-like restriction, not often enough to make it
> worthwhile.  With garbage-collection of closures, it would probably be
> worthwhile, but we probably don't want to go there; and for something in
> between, we will have to see.

MINOS uses a lot of closure-like objects+quotations, the "actions".  An 
action is bound to a widget, contains a state variable of its own (e.g. 
on/off for a toggle button), and an action (or two), stored as quotation 
xt; the quotation is performed in the context of the object that created 
those actions and widgets.  Since all that commons stuff is reused again 
and again, it's just a slightly different version of [: ;] around a block 
of code to instantiate them.  So the line count is probably not a problem.

In Common Lisp, you would do that with closures.  In an OOP system, you 
do it with OOP.  And if you want a more compact format of declaring 
things, just define them.  You could have an OOP system that declares the 
class in one line, and creates you an instantiation code that takes the 
initial values from stack, just with about the same amount of code we 
need to implement locals (a lot more code than mini-oof2.fs).

<base class> O{ k x1 x2 x3 x4 x5 }O mob

certainly is possible.  There's even a mini-oof.fs based implementation 
of closures, which does just that.  If we wanted to generalize the locals 
declaration, we could easily reuse most of the code in glocals.fs; after 
all, the declaration of a set of locals and the declaration of a set of 
instance variables is the same problem: Create a bunch of names which 
address consecutive elements in memory; one time on a locals stack, 
another time in an object.  And Algol 60 even recognizes that by calling 
the locals "activation record".

If you look at the Rosetta code page of the man-or-boy test, you'll find 
a number of implementations which use classes to implement the activation 
record, so I think that approach is fair and useful.

http://rosettacode.org/wiki/Man_or_boy_test

If you want a class creation syntax which reduces line count, it's also 
doable.  mini-oof2.fs just shares code with the structure declaration, 
sharing code with the locals declaration would also be possible.

-- 
Bernd Paysan
"If you want it done right, you have to do it yourself"
net2o ID: kQusJzA;7*?t=uy@X}1GWr!+0qqp_Cn176t4(dQ*
http://bernd-paysan.de/

[toc] | [prev] | [next] | [standalone]


#50449

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2016-08-24 15:54 +0000
Message-ID<2016Aug24.175406@mips.complang.tuwien.ac.at>
In reply to#50412
Bernd Paysan <bernd.paysan@gmx.de> writes:
>In Common Lisp, you would do that with closures.  In an OOP system, you 
>do it with OOP.

Somehow, in the last few years, several popular object-oriented
languages, e.g., Java, C++, and C#, have acquired lambdas; apparently
not everybody does it with OOP.

And actually you are not using the distinctive feature of OOP: dynamic
binding.  What you use, is the current-object pointer.  However, this
allows access only to locals from one activation record; that's enough
for the man-or-boy test, but not in the general case.  Is the general
case needed?  Yes, in particular in curried functions each argument is
in a separate activation record.

>And if you want a more compact format of declaring 
>things, just define them.  You could have an OOP system that declares the 
>class in one line, and creates you an instantiation code that takes the 
>initial values from stack, just with about the same amount of code we 
>need to implement locals (a lot more code than mini-oof2.fs).
>
><base class> O{ k x1 x2 x3 x4 x5 }O mob
>
>certainly is possible.  There's even a mini-oof.fs based implementation 
>of closures, which does just that.  If we wanted to generalize the locals 
>declaration, we could easily reuse most of the code in glocals.fs; after 
>all, the declaration of a set of locals and the declaration of a set of 
>instance variables is the same problem: Create a bunch of names which 
>address consecutive elements in memory; one time on a locals stack, 
>another time in an object.

Is the locals-derived "class" definition useful for anything besides
locals?

Of course, if we support non-local locals, we will have to enhance the
locals code to create activation records when needed, and also to
create the access to the right activation record.  The definition part
is similar to a structure or class definition, but the access part is
quite different for the general case.

We also need a way to specify how an activation record is allocated
and how long it lives.  E.g., for something CREATE-DOES>-like we want
to ALLOT the memory:

: constant ( x "name" -- )
  ['] here-allot <{: x :}
  [: x :] <create ;

This would allot the activation record (and HERE-ALLOT is an ALLOT
that returns the address of the allotted memory), and at run-time it
accesses the local and return it.

>If you look at the Rosetta code page of the man-or-boy test, you'll find 
>a number of implementations which use classes to implement the activation 
>record, so I think that approach is fair and useful.

I also find that the C++11 and C# version 3+ have shorter source code
by using anonymous functions/lambda expressions.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2016: http://www.euroforth.org/ef16/

[toc] | [prev] | [next] | [standalone]


#50511

FromBernd Paysan <bernd@net2o.de>
Date2016-08-28 00:43 +0000
Message-ID<nptc44$o3r$2@dont-email.me>
In reply to#50449
Am Wed, 24 Aug 2016 15:54:06 +0000 schrieb Anton Ertl:

> And actually you are not using the distinctive feature of OOP: dynamic
> binding.  What you use, is the current-object pointer.  However, this
> allows access only to locals from one activation record; that's enough
> for the man-or-boy test, but not in the general case.  Is the general
> case needed?  Yes, in particular in curried functions each argument is
> in a separate activation record.

What about this part of my source code was not clear to you?

object class
    field: k
    method b
end-class mob

:noname ( -- n ) k @ ; mob to b \ bind xt to b of mob

...

:noname ( -- n )
    -1 k +!
    k @ o x1 @ x2 @ x3 @ x4 @ a
; b-ctx to b \ bind xt to b of b-ctx

Method b is dynamically bound to either work for the constants or for the 
recursive call.

Note that the lambda closures in C++ and Java are syntactic sugar around 
classes, they aren't implemented the same way as you would do it in Algol 
60.  C++ overloads the function call to make it happen, which actually 
means that you can't pass a lambda closure to a function that takes a 
normal function pointer.

Only lambdas without any captured variables are compatible with function 
pointers, all others need std::function as type.

http://www.cprogramming.com/c++11/c++11-lambda-closures.html

In Java, it was easier, as Java didn't have any function pointer type to 
start with.  Now it has one, and it's just calling a specified method of 
a particular class, something Java's VM can do.

-- 
Bernd Paysan
"If you want it done right, you have to do it yourself"
net2o ID: kQusJzA;7*?t=uy@X}1GWr!+0qqp_Cn176t4(dQ*
http://bernd-paysan.de/

[toc] | [prev] | [next] | [standalone]


#50512

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2016-08-28 09:53 +0000
Message-ID<2016Aug28.115350@mips.complang.tuwien.ac.at>
In reply to#50511
Bernd Paysan <bernd@net2o.de> writes:
>Am Wed, 24 Aug 2016 15:54:06 +0000 schrieb Anton Ertl:
>
>> And actually you are not using the distinctive feature of OOP: dynamic
>> binding.  What you use, is the current-object pointer.  However, this
>> allows access only to locals from one activation record; that's enough
>> for the man-or-boy test, but not in the general case.  Is the general
>> case needed?  Yes, in particular in curried functions each argument is
>> in a separate activation record.
>
>What about this part of my source code was not clear to you?

What makes you think that it is not clear to me?

>Note that the lambda closures in C++ and Java are syntactic sugar around 
>classes, they aren't implemented the same way as you would do it in Algol 
>60.

Earlier you argued that activation records and objects are the same thing.

I see two differences:

* Objects are connected to dynamic binding of methods, something that
  is not needed for activation records.  But that extra capability
  does not hurt when implementing activation records with objects.

* Object-oriented languages normally have only one current object
  (this or self), while there several activation records can be active
  at the same time, one for each outer function that has local
  variables.  That is what I was pointing out above.

  As a minimal example, consider a curried implementation
  of ROT in a dialect of Forth with full closures:
  
  : crot { x } [: { y } [: { z } y x z ;] ;] ;
  1 2 3 crot execute execute \ now on the stack: 2 3 1
  
  Here you have an activation record containing X, and another
  activation record containing Y, and you cannot keep both of those in
  the current object, but need to implement some additional mechanism
  to perform the access; in cases with read-only locals like this one,
  you can shift the additional work to the definition (by also
  defining a copy of X in the Y activation record, and maybe copies of
  X and Y in the Z activation record). 

  But in cases with locals that are changed, you cannot do that.  The
  classical implementations are to use a static link chain or a
  display, but the C++ syntax suggests keeping the addresses of the
  accessed variables in the later activation records (one can also see
  this as a variation on the display theme).  Anyway, all of this
  requires something that's a bit different from an ordinary
  object-oriented field access.

>C++ overloads the function call to make it happen, which actually 
>means that you can't pass a lambda closure to a function that takes a 
>normal function pointer.
>
>Only lambdas without any captured variables are compatible with function 
>pointers, all others need std::function as type.
>
>http://www.cprogramming.com/c++11/c++11-lambda-closures.html

My guess is that this difference between ordinary function pointers
and std::function is that ordinary function pointers are C-compatible
and don't come with an environment, while std:function includes an
environment.  They apparently did not want to go for trampolines, and,
after all they are C++: Introducing yet another type and then trying
to hide it with overloading is their way of life.

>In Java, it was easier, as Java didn't have any function pointer type to 
>start with.  Now it has one, and it's just calling a specified method of 
>a particular class, something Java's VM can do.

The hard part for Java apparently was to make it fit in the type
system (at least my colleague who is into type systems tells me that).
Fortunately we don't have that problem in Forth.

Anyway, both languages have added lambdas, however implemented,
because they allow expressing programs more succinctly than with just
the object-oriented features they had before.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2016: http://www.euroforth.org/ef16/

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.forth


csiph-web