1. Plans for Euphoria

It's only been a few hours and I already have a list of stuff I'm going to do
with the code. Go figure. Anyways here's what I'm planning to add and would like
feedback on whether it'd be a good or bad idea.


perform
-------

Syntax:

<variable> = perform <code> end perform

Description:

Keyword to allow pseudo-anonymous functions. It is essentially a self-contained
body of code that is run once and returns a value.

Example:

-- Read all the text from the config file
constant CONFIG_FILE_CONTENTS = perform 
    sequence result
    object line
    line = gets(config_fn)
    while sequence(line) do
        result = append(result, line)
        line = gets(config_fn)
    end while
end perform



foreach
-------

Syntax:

foreach <variable> in <sequence> do <code> end foreach

Description:

Same as:
    for i=1 to length(string) do
        char = str[i]
        if char ...
    end for
Loops through each element of a sequence and allows you to use the variable to
refer to that element. 95+% of all for loops in Euphoria do essentially this
except with more typing. Element variable will most likely be read only to mirror
the for loop variable.

Example:

-- Go through a list of people and make a list of the names of all adults
sequence legal_adults
foreach person in client_list do
    if person[AGE] >= 18 then
        legal_adults = append(legal_adults, person[NAME])
    end if
end foreach



sequence of
-----------

Syntax:

sequence of <type> <variable>

Description:

Allows you to define a sequence where every element sequence must be of a
specific type.

Example:

-- Get the name of a file and open it saving the file handle in a list
sequence of integer file_handles
integer fn
file_handles = {}
while length(file_handles) < 30 do -- Only 30 files can be opened
    fn = open(prompt_string("Name of next file:"), "r")
    if fn > -1 then
        file_handles &= fn
    end if
end while


Local Constants
---------------

Syntax:

[function|procedure] <name>(<arguments>)
    constant <name> = <value>
    <code>
end [function|procedure]

Description:

I want to allow users to declare constants locally inside functions and
procedures. This is something that I have constantly found limiting because I've
wanted to declare sequence indeces as constants for use in one function but have
to declare them for use in all following code. Plus, it's logical. Why can you
declare local variables but not local constants since they are practically the
same?

Example:

-- `distance` returns the distance between two points
function distance(point a, point b)
    constant X = 1, Y = 2
    return sqrt(power(b[X] - a[X], 2) + power(b[Y] - a[Y], 2))
end function  -- distance



Those are the only things I'm currently thinking about adding to the language.
I've needed foreach so much that I wrote my own pre-parser to do it for me which
has a big overhead. perform came to me during all those times I've defined a
constant and needed to check every element of a sequence before setting it (if
you can do it in Lisp why not Euphoria?).

Besides trying to add stuff I'm going to port Euphoria to as many OSes as
possible. My first platform is going to be the PowerMac so I can use it at work
followed by hopefully either ZETA and/or the BSDs (ZETA would require more work
but I don't have a OpenBSD or NetBSD computer right now). A Mac port is
essentially guaranteed at this point because even if I don't have the time to do
it I know other people that really want Euphoria on the Mac as well who would be
quite happy to do it.

new topic     » topic index » view message » categorize

2. Re: Plans for Euphoria

I think those are pretty good ideas.

I would like to present some of my ideas from VEEU in the future. But I'm
currently busy with school and don't have time to work on the source code.
Perhaps this holiday season and the following summer I'll have spare time.


Regards,
Vincent

new topic     » goto parent     » topic index » view message » categorize

3. Re: Plans for Euphoria

D. Newhall wrote:

> It's only been a few hours and I already have a list of stuff I'm going to do
> with the code. Go figure. Anyways here's what I'm planning to add and would
> like feedback on whether it'd be a good or bad idea.

OK, I'll give my personal opinions regarding the items on your list.


> perform
> -------
> 
> Syntax:
> 
> <variable> = perform <code> end perform
> 
> Description:
> 
> Keyword to allow pseudo-anonymous functions. It is essentially a
> self-contained
> body of code that is run once and returns a value. 
> 
> Example:
> 
> -- Read all the text from the config file
> constant CONFIG_FILE_CONTENTS = perform 
>     sequence result
>     object line
>     line = gets(config_fn)
>     while sequence(line) do
>         result = append(result, line)
>         line = gets(config_fn)
>     end while
> end perform

Sorry, I can't see what we'd gain by this new keyword.
We can now do the same as in your example by using a normal function:

function read_config()
    -- Read all the text from the config file
    sequence result
    object line
    line = gets(config_fn)
    while sequence(line) do
        result = append(result, line)
        line = gets(config_fn)
    end while
end function
constant CONFIG_FILE_CONTENTS = read_config()



> foreach
> -------
> 
> Syntax:
> 
> foreach <variable> in <sequence> do <code> end foreach
> 
> Description:
> 
> Same as:
>     for i=1 to length(string) do
>         char = str[i]
>         if char ...
>     end for
> Loops through each element of a sequence and allows you to use the variable
> to refer to that element. 95+% of all for loops in Euphoria do essentially
> this
> except with more typing. Element variable will most likely be read only to
> mirror
> the for loop variable.
> 
> Example:
> 
> -- Go through a list of people and make a list of the names of all adults
> sequence legal_adults
> foreach person in client_list do
>     if person[AGE] >= 18 then
>         legal_adults = append(legal_adults, person[NAME])
>     end if
> end foreach

This is nice "syntactic sugar" IMHO, which can _increase readability_ of the
code. (It's almost impossible to overestimate the importance of readability.)


> sequence of
> -----------
> 
> Syntax:
> 
> sequence of <type> <variable>

Just a short note:
I'm pretty sure you mean

sequence of <type> <variable> [, <variable>, ...]

so that it'd be possible to declare more than one variable after
'sequence of <type>', no?

> Description:
> 
> Allows you to define a sequence where every element sequence must be of a
> specific
> type.
> 
> Example:
> 
> -- Get the name of a file and open it saving the file handle in a list
> sequence of integer file_handles
> integer fn
> file_handles = {}
> while length(file_handles) < 30 do -- Only 30 files can be opened
>     fn = open(prompt_string("Name of next file:"), "r")
>     if fn > -1 then
>         file_handles &= fn
>     end if
> end while

I would appreciate this.
Currently, I do something similar by using user-defined types, e.g.
   sequence_of_integer x, y, z

This works fine, but the problem is that this way type-checking sometimes
can take a long time! Your suggested method should work considerably faster,
otherwise I can't see an advantage.


> Local Constants
> ---------------
> 
> Syntax:
> 
> [function|procedure] <name>(<arguments>)
>     constant <name> = <value>
>     <code>
> end [function|procedure]
> 
> Description:
> 
> I want to allow users to declare constants locally inside functions and
> procedures.
> This is something that I have constantly found limiting because I've wanted
> to declare sequence indeces as constants for use in one function but have to
> declare them for use in all following code. Plus, it's logical. Why can you
> declare local variables but not local constants since they are practically the
> same?
> 
> Example:
> 
> -- `distance` returns the distance between two points
> function distance(point a, point b)
>     constant X = 1, Y = 2
>     return sqrt(power(b[X] - a[X], 2) + power(b[Y] - a[Y], 2))
> end function  -- distance

I agree that this would be a useful and logical enhancement.

<snip>

Regards,
   Juergen

new topic     » goto parent     » topic index » view message » categorize

4. Re: Plans for Euphoria

D. Newhall wrote:
> 
> It's only been a few hours and I already have a list of stuff I'm going to do
> with the code. Go figure. Anyways here's what I'm planning to add and would
> like feedback on whether it'd be a good or bad idea.
> 
> 
> perform
> -------
> 
> Syntax:
> 
> <variable> = perform <code> end perform
> 
> Description:
> 
> Keyword to allow pseudo-anonymous functions. It is essentially a
> self-contained
> body of code that is run once and returns a value. 
> 
> Example:
> 
> -- Read all the text from the config file
> constant CONFIG_FILE_CONTENTS = perform 
>     sequence result
>     object line
>     line = gets(config_fn)
>     while sequence(line) do
>         result = append(result, line)
>         line = gets(config_fn)
>     end while
> end perform
> 
> 
> foreach
> -------
> 
> Syntax:
> 
> foreach <variable> in <sequence> do <code> end foreach
> 
> Description:
> 
> Same as:
>     for i=1 to length(string) do
>         char = str[i]
>         if char ...
>     end for
> Loops through each element of a sequence and allows you to use the variable
> to refer to that element. 95+% of all for loops in Euphoria do essentially
> this
> except with more typing. Element variable will most likely be read only to
> mirror
> the for loop variable.
> 
> Example:
> 
> -- Go through a list of people and make a list of the names of all adults
> sequence legal_adults
> foreach person in client_list do
>     if person[AGE] >= 18 then
>         legal_adults = append(legal_adults, person[NAME])
>     end if
> end foreach
> 
> 
> sequence of
> -----------
> 
> Syntax:
> 
> sequence of <type> <variable>
> 
> Description:
> 
> Allows you to define a sequence where every element sequence must be of a
> specific
> type.
> 
> Example:
> 
> -- Get the name of a file and open it saving the file handle in a list
> sequence of integer file_handles
> integer fn
> file_handles = {}
> while length(file_handles) < 30 do -- Only 30 files can be opened
>     fn = open(prompt_string("Name of next file:"), "r")
>     if fn > -1 then
>         file_handles &= fn
>     end if
> end while
> 
> 
> Local Constants
> ---------------
> 
> Syntax:
> 
> [function|procedure] <name>(<arguments>)
>     constant <name> = <value>
>     <code>
> end [function|procedure]
> 
> Description:
> 
> I want to allow users to declare constants locally inside functions and
> procedures.
> This is something that I have constantly found limiting because I've wanted
> to declare sequence indeces as constants for use in one function but have to
> declare them for use in all following code. Plus, it's logical. Why can you
> declare local variables but not local constants since they are practically the
> same?
> 
> Example:
> 
> -- `distance` returns the distance between two points
> function distance(point a, point b)
>     constant X = 1, Y = 2
>     return sqrt(power(b[X] - a[X], 2) + power(b[Y] - a[Y], 2))
> end function  -- distance
> 
> 
> Those are the only things I'm currently thinking about adding to the language.
> I've needed foreach so much that I wrote my own pre-parser to do it for me
> which
> has a big overhead. perform came to me during all those times I've defined a
> constant and needed to check every element of a sequence before setting it (if
> you can do it in Lisp why not Euphoria?).
> 
> Besides trying to add stuff I'm going to port Euphoria to as many OSes as
> possible.
> My first platform is going to be the PowerMac so I can use it at work followed
> by hopefully either ZETA and/or the BSDs (ZETA would require more work but I
> don't have a OpenBSD or NetBSD computer right now). A Mac port is essentially
> guaranteed at this point because even if I don't have the time to do it I know
> other people that really want Euphoria on the Mac as well who would be quite
> happy to do it.

foreach is desperately needed. However, I see a problem with the way you explain
it.
For this to be useful, you need both an index, because you may have decisions 
to make on the index, and the element value. So perhaps something like
foreach char [at idx [from start_index ][to somewhere ][by some_step]] in string
do
-- code where idx incrementing and char=string[idx] always
end foreach


You may forget idx if you don't need it. If some_step is negative, I'd expect
 idx to start at length(string). Both char and idx would look like current 
for loop indexes I bet (undeclared, local to the for loop).

Also, do you plan to care for the case where string gets modified in 
structure during the process?

Local constants are just fine.

As for perform, why not just write:
constant my_computed_constant(perhaps with parameters)
-- some code here
end constant


This would make my_computed_constant a constant, initialised the first time 
the routine code inside the block is run. Isn't that simpler?


CChris

new topic     » goto parent     » topic index » view message » categorize

5. Re: Plans for Euphoria

On Tue, 17 Oct 2006 22:48:31 -0700, "D. Newhall"
<guest at RapidEuphoria.com> wrote:

>here's what I'm planning to add and would like feedback on whether it'd be a
>good or bad idea.

><variable> = perform <code> end perform
Can't see the point of this.
>constant CONFIG_FILE_CONTENTS = perform 
>    sequence result
>    object line
Are you implying a) the constant is set to 'result' and a compilation
error occurs if there is no variable named result defined in the code
block, or b) the constant is set to the first defined variable?
Why use result at all, why not CONFIG_FILE_CONTENTS?
What else would you use this for other than constants and what exactly
is the benefit over a simple function? Why not use function() for a
nameless, parameterless function instead of perform?
Later, you wrote:
>perform came to me during all those times I've defined a constant and 
>needed to check every element of a sequence before setting it (if you 
>can do it in Lisp why not Euphoria?).
I suspect there is something else here, what are you trying to say?


>foreach <var> in <seq> do <code> end foreach
<snip>
>Loops through each element of a sequence and allows you to use the variable to
>refer to that element.
>95+% of all for loops in Euphoria do essentially this except with more typing.
I read that as you agreeing with me that foreach is wholly
inappropriate in probably 5% of all cases (though I might be a bit
higher than 5%, "some", anyway).

I think this should be a restricted case and equivalent to say:
for <tmpi> = 1 to length(<seq>) do
    <var>=<seq>[<tmpi>]
    <seq>[<tmpi>]=0		-- reduce ref count
    <code>
    <seq>[<tmpi>]=<var>
end for
<var>=0			-- reduce ref count

With the following notes:
 <seq> is read-only throughout the loop (though you can modify <var>)
 <tmpi> is an internal index and cannot be examined by the program.
 If you want to know the subscript index of <seq> currently being 
  processed, use a normal for i=1 to length() loop, as you should if
  any problems arise, such as calling a routine which crashes because
  some element of <seq> is temporarily 0.
 Type checking does not occur on the <seq>[<tmpi>]=0 line, though it
  does on the <seq>[<tmpi>]=<var> line (if not optimised away: -- if 
   <var> not modified anywhere in the loop, delete 2 lines above). 

>Element variable will most likely be read only to mirror the for loop variable.
As above I would go the other way and make <seq> read only.

If you have both an index and <var>, then you can't really stomp on
<seq>[i] as I suggest, which means your ref counts are stuffed, so I
have to boldly split my infinitives and strongly disagree with CChris.


>sequence of
This is non-trivial!
I think the real case goes something like this:
type something(...) end type
sequence of something TabS

Now,
TabS[37]=x

calls something(), just once, not length(TabS) times, however:
TabS=X

Must invoke something() length(X) times, unless X is the same type,
in which case it does not need to call it at all, unless it has side
effects [same deal for the TabS[37]= case].

Fun and games with &, append, prepend, slice assignment, etc...

One particular optimisation might be sequence of float: each element
of such a beast is a 64-bit float rather than a 32-bit pointer to a
64-bit float. Not for the faint hearted!

"sequence of char" is a really daft way to implement strings (unless
you really, really want to test each character quite often).

Also consider the following: 
type a(sequence of integer x)
    type b(sequence of a y)
    type c(sequence of b z)
    sequence of c d

When d[i] is assigned, we invoke c, which invokes b etc...
When d[i][j] is assigned, we may get away with invoking b only.
If you were to allow eg:
sequence of sequence of sequence of sequence of integer d

then I think you'd have to emit 'anonymous' type definitions similar
to a..c above.

Lastly, "of object" should either trigger an error message or be
completely ignored, it is not sensible to invoke object() at run-time;
even if the programmer explicitly codes a call, the compiler can just
replace it with a literal 1.

As for advice? If you want "sequence of", forget Eu sources and start
the whole thing from scratch - you'll finish it faster!


>Local Constants
Agree. I also thought of static vars, functionally identical to
defining them just a few lines earlier, so they keep their value
between calls, but their scope is restricted within the routine.
Allowing constants like this also begs a full implementation of
assignment on declaration.

Regards,
Pete

new topic     » goto parent     » topic index » view message » categorize

6. Re: Plans for Euphoria

Juergen Luethje wrote:
> 
(snip)
> > perform
> > -------
> > 
> > Syntax:
> > 
> > <variable> = perform <code> end perform
> > 
> > Description:
> > 
> > Keyword to allow pseudo-anonymous functions. It is essentially a
> > self-contained
> > body of code that is run once and returns a value. 
> > 
> > Example:
> > 
> > -- Read all the text from the config file
> > constant CONFIG_FILE_CONTENTS = perform 
> >     sequence result
> >     object line
> >     line = gets(config_fn)
> >     while sequence(line) do
> >         result = append(result, line)
> >         line = gets(config_fn)
> >     end while
> > end perform
> 
> Sorry, I can't see what we'd gain by this new keyword.
> We can now do the same as in your example by using a normal function:
> 
> }}}
<eucode>
> function read_config()
>     -- Read all the text from the config file
>     sequence result
>     object line
>     line = gets(config_fn)
>     while sequence(line) do
>         result = append(result, line)
>         line = gets(config_fn)
>     end while
> end function
> constant CONFIG_FILE_CONTENTS = read_config()
> </eucode>
{{{


The whole point is that you don't have to do that. Most people structure there
code the same way; include files, global constants, global variables,
procedures/functions, then the rest of the code. Having to define a function at
the start of your program just to set a constant adds complexity and makes the
code harder to read and understand.


> > sequence of
> > -----------
> > 
> > Syntax:
> > 
> > sequence of <type> <variable>
> 
> Just a short note:
> I'm pretty sure you mean
> 
> sequence of <type> <variable> [, <variable>, ...]
> 
> so that it'd be possible to declare more than one variable after
> 'sequence of <type>', no?

That's correct. Accidentally left that part out.

(snip)

new topic     » goto parent     » topic index » view message » categorize

7. Re: Plans for Euphoria

CChris wrote:
> 
(snip)
> 
> foreach is desperately needed. However, I see a problem with the way you
> explain
> it.
> For this to be useful, you need both an index, because you may have decisions
> 
> to make on the index, and the element value. So perhaps something like
> }}}
<eucode>
> foreach char [at idx [from start_index ][to somewhere ][by some_step]] in
> string do
> -- code where idx incrementing and char=string[idx] always
> end foreach
> </eucode>
{{{

> 
> You may forget idx if you don't need it. If some_step is negative, I'd expect
>  idx to start at length(string). Both char and idx would look like current 
> for loop indexes I bet (undeclared, local to the for loop).

You don't need all of that actually since you can just do:

foreach char in string[start_index..somewhere] do
    ...
end foreach

and to go backwards from somewhere to start_index:

foreach char in reverse(string[start_index..somewhere]) do
    ...
end foreach

Having a step value might be useful though.

> Also, do you plan to care for the case where string gets modified in 
> structure during the process?

I'm going to say probably not just like we can't change a sequence while
assigning to a slice of it.


> As for perform, why not just write:
> }}}
<eucode>
> constant my_computed_constant(perhaps with parameters)
> -- some code here
> end constant
> </eucode>
{{{

> 
> This would make my_computed_constant a constant, initialised the first time
> 
> the routine code inside the block is run. Isn't that simpler?

Simpler perhaps, but harder to read I'd say since it looks just like a function
or procedure definition. Also, perform could be used for any variable/value not
just constants.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu