[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon Dec 30 04:10:22 2003 
Subject:Re: Euphoria -- a pop11-like language 
From:steve 
Volume-ID:1031230.07 

Hi,

Aaron writes:
>I've just discovered Euphoria, a language which appears to be very like
>a subset of pop11, but with some interesting differences.

I've gone through the reference manual in enough detail to make
some sensible comments.  My quick summary is that Euphoria is not
likely to be of much interest to Pop-11 programmers.  But read on for
more details.

The following comments are really pitched towards the readers of
this list whom I presume are fairly familiar with Poplog and
especially Pop-11 and Lisp.  This is, perhaps, an unfair perspective
since Euphoria is highly minimalist work and Poplog is a sophisticated,
mature system.

But, let's position Euphoria in the pantheon of languages.
It is dynamically typed, but lacks first class procedures, lacks any
kind of class structure, and does not permit the creation of new
types (although a interesting kind of subtyping is allowed.)  It does
have automatic memory management which, though not clearly specified,
is probably reference counting.  Like Lisp, Pop-11 and Java, arguments
are shallowly copied i.e. structure sharing is normal.  There is no
package system.  Nor is there any form of non-sequential processing
i.e. exceptions, coroutines, threads or tasks.

The set of datatypes are extremely restricted: numbers and vectors which
are called atoms and sequences in Euphoria.  Although it is not
explicitly stated, it appears that numbers are limited to double
precision floating points.  In particular there is no support for
bignums, ratios or complex numbers.  There is no support for multi
dimensional arrays nor "associative" arrays.  As mentioned above, users
have no means of introducing new types - so numbers and vectors is
it.

It should be noted that there are no separate primitive types for
boolean (use 0 or non-0), character (use small number), or string
(use a vector of numbers).  However, like Prolog, there is limited
lexical support for denoting characters and strings.

The main emphasis of design has been on making the operators work
hard.  These are the arithmetic and relational operators, assignment
and concatenation
    + - / *           arithmetic
    < > <= >= != =    relational
    =                 assign
    &                 concatenate
One point of note is that the same symbol is employed for both
equality and assignment - an ambiguity which is allowed by the
strong grammatical distinction between statements and expressions.

In common with other languages in which arrays are the main type
(e.g. FP, APL) the operators work with both scalar and vector types.
The general pattern for a scalar operator OP
  scalar1 OP scalar2 -> scalar
is that it pairwise "zips" vector together
   vector1 OP vector2 -> { for i, j in vector1, vector2 do i OP j endfor }
and that
   scalar OP vector -> { repeat length( vector ) times scalar } OP vector
and
   vector OP scalar -> vector OP { repeat length( vector ) times scalar }

The notable exception to the above is the concatenation operator since it
is not considered to be an n-ary operator rather than a binary operator.

One of the consequences of this pattern is that the relational operators
yield vectors of 0|1s when applied to vectors.  Hence vectors cannot be
compared for equality using the "=" operator but a special equality
operator must be used.  Hence "=" should really be thought of as
"numerical equality".

Vectors can be indexed using usual
	VAR[ EXPR ]
notation, although the VAR is restricted to being a variable
and not a full expression (no reason given).  However, a slicing
operator is provided
	VAR[ EXPR .. EXPR ]
which can be run in update mode
	VAR[ EXPR .. EXPR ] = EXPR
In this latter form there appears to be a form of dynamic coercion to
make the right hand side congruent to the slice.  If this is true, we
are guaranteed that the VAR has the same length before and after the
assignment.

As can be seen, vectors are mutable but, so far as I can seen, they
are inextensible.  (I'm not sure about this since experiment seems to
indicate that the implementation is in terms of a hash table.  If
so, surely they would be extensible?)

Routines are divided into two grammatical categories: functions and
procedures.  Functions must return a result but procedures must not.
Because there is an explicit "return" statement, it is unclear why
this distinction is made.  I would hazard a guess that this is because
there is only limited checking that all branches of a function
execute a "return" - in which case a function appears to return 1
(although this is not documented).  There are no updaters.

Routines may not nest - hence all variables are either global or
local and there are no scope issues of interest.  Although function
variables cannot be referred to as ordinary variables ("pushed" in Poplog
parlance) they do occupy the same name space.  They can be referred to
very clumsily via internal integer IDs, however.  This mechanism
is used whenever mutual recursion is required.

There is a special constant declaration which is not permitted inside
routines (no reason given).  These are assign-once variables.  This is
exactly the same as Pop-11's constant declaration with the same
oddball limitation!

Ordinary variable declarations look like this
    sequence x
    integer y
It is possible to introduce new type declarators via a simple subtyping
mechanism.  The example given in the manual is as good as any:

        type hour(integer x)
            return x >= 0 and x <= 23
        end type

        hour h1, h2

        h1 = 10      -- ok
        h2 = 25      -- error! program aborts with a message

In other words, hour is a restricted subset of integers that meets the
defined test.

The control statements are the usual familiar set: there is a cascaded-if,
a while statement, and a BASIC like for loop
	for i = 1 to 10 do STATEMENTS end for
Note that the for loop declares its loop variable implicitly.  The
for loop is limited to a single variable and there is no "for i in vector"
form.  However, there is an early loop exit provided by the "exit"
keyword - but it appears to be limited to exiting to the immediately
enclosing loop.  For completeness, it should be mentioned that there
is a "return" statement.  None of these can be used as expressions.

Two short-circuit operators and + or are provided.  These operators
behave differently when used as the predicate for an if/while-statement
from when they are used in a general expression.  In the former case
they short-circuit, in the latter case they do not.  The manual firmly
states that this is deliberate - in order to support the following
idiom
    x = 1 or { 2 }    --- assigns {2} not 1

Little more needs to be said.  Syntactically it appears to be
conventional.  In its favour the control constructs are all of the form
    KEYWORD ...... end KEYWORD
and the cascading-if is designed correctly.

-- 
Steve