Céu v0.20 (not complete yet)

40 views
Skip to first unread message

Francisco Sant'anna

unread,
Oct 6, 2016, 10:10:00 PM10/6/16
to ceu-...@googlegroups.com
Hi,

I've been working quietly on a new version.
These are the most important changes:
- new implementation from scratch
- new command-line interface
- removing organisms in favor of "code/await".
It should be much easier now to install and compile the examples from the repositories above.

Hope more comes soon...

Francisco

Matthias T.

unread,
Oct 7, 2016, 2:55:01 AM10/7/16
to The Programming Language Céu
Hi,

great work! I am looking forward very much to tryout version v0.20 :-)

Is it possible to provide a specific commit indicating the latest (most current) version of v0.10? Your tag https://github.com/fsantanna/ceu/commit/9ce60f87f847ddda0f7f641e18e6825781811c87 appears to be considerably outdated.

Thanks and regards,
Matthias

Francisco Sant'anna

unread,
Oct 7, 2016, 5:05:28 AM10/7/16
to ceu-...@googlegroups.com
On Fri, Oct 7, 2016 at 3:55 AM, Matthias T. <matthia...@gmail.com> wrote:
Hi,

great work! I am looking forward very much to tryout version v0.20 :-)

Is it possible to provide a specific commit indicating the latest (most current) version of v0.10? Your tag https://github.com/fsantanna/ceu/commit/9ce60f87f847ddda0f7f641e18e6825781811c87 appears to be considerably outdated.

Sure, thanks for the remind.
I'm using the tag v0.12b for the previous never released version (with the "arch/" directory).

Regards,
Francisco

Job van der Zwan

unread,
Oct 7, 2016, 6:48:50 AM10/7/16
to The Programming Language Céu
So good to see Céu is still alive and being developed! :)

I'm doing webdev these days (because work and necessity of being able to buy food) and I don't dabble in other languages as much on the side as I used to, but I'm still following the development of Céu


On Friday, 7 October 2016 04:10:00 UTC+2, Francisco Sant'Anna wrote:
- removing organisms in favor of "code/await".

So I've read the Birds examples and it looks pretty clean (btw, in examples seven to twelve you're defining PI twice - remove the top two lines to make it consistent with the examples before it). I guess the key insight is: 

- one could combine the first-class concurrency of Céu with functions to easily write a functions that pause and resume reactively on their own
- functions can have local variables, hence local state,
- together this pretty much supersedes the need for objects, since you can just spawn reactive functions

Did I grok that correctly? And does this mean that code/tight is basically for defining non-concurrent function?

(also this really shows how confusing labels like "functional programming" and "imperative programming" are, because this looks like a happy fusion of the two)

I'm liking the newly introduced notations a lot as well. At least I don't remember this one:

> loop i in [0->5[ do

My guess is "from 0 up to 5 (not including)", is that correct? If so, cool way of describing inclusive/exclusive ends! Never thought of using reversed brackets to represent open/closed ranges of math notation. The code/await syntax looks Maths-notation inspired (in a good way) as well.

Céu always had this eclectic mix of being a high-level human-readable language on the one hand (I think you had a blog-post about why you switched to human-understandable words instead of Esterel's operators), and on the other having low-level "pointy" bits sticking through with human-unfriendly syntax straight from the seventies. It feels a bit jarring at times, and smoothing those pointy bits out (without giving up power) is a good direction to go, I think.

Speaking of notation, is there a way around this amount of extra bookkeeping?

  var&? SDL_Rect rct1;
  event&? void col1;
  loop (rct1,col1) in birds do
    ..
  end

Wouldn't the types of rct1 and col1 already be known to the compiler, because it's a pool of Birds? Similarly, there's this:


    code/await Bird (var int y, var int speed)
                        => (var&? SDL_Rect rct, event&? void go_collided)
                            => void
    do
        var SDL_Rect rct_ = val SDL_Rect(20,y, 50,45);
        rct = &rct_;


Which feels like the kind of type accounting that the computer should be able to automate away for you, maybe like so:

    code/await Bird (var int y, var int speed)
                        => (var&? SDL_Rect rct, event&? void go_collided)
                            => void
    do
        rct = &val SDL_Rect(20,y, 50,45);

This is of course ignoring that things like type inference being a lot of work to implement, and I totally understand that you have to prioritise.

How is overall performance (both size and speed wise) compared to v0.10? Will there be Arduino builds soon?

Anyway, really excited about the release, I wish I could make time to just fool around with the language more :)

Francisco Sant'anna

unread,
Oct 7, 2016, 9:13:35 AM10/7/16
to ceu-...@googlegroups.com
On Fri, Oct 7, 2016 at 7:48 AM, Job van der Zwan <j.l.van...@gmail.com> wrote:
So good to see Céu is still alive and being developed! :)

Thank you. Unfortunately, Github only marks contributions to the "master" branch.
The development has been continuous since the beginning. I now have a stable situation in an University (unless the State breaks, which is not completely unlikely). :)

I'm doing webdev these days (because work and necessity of being able to buy food) and I don't dabble in other languages as much on the side as I used to, but I'm still following the development of Céu

That's great. You contribute a lot with your insights here. Keep with us.
 
On Friday, 7 October 2016 04:10:00 UTC+2, Francisco Sant'Anna wrote:
- removing organisms in favor of "code/await".

So I've read the Birds examples and it looks pretty clean (btw, in examples seven to twelve you're defining PI twice - remove the top two lines to make it consistent with the examples before it).

Fixed.
 
I guess the key insight is: 

- one could combine the first-class concurrency of Céu with functions to easily write a functions that pause and resume reactively on their own
- functions can have local variables, hence local state,
- together this pretty much supersedes the need for objects, since you can just spawn reactive functions

Did I grok that correctly?

Yes. But to fully supersede organisms we need some form to interact with the "code/await" during its execution (it's not only start->forget->get results).
There are two forms to make this happen:
- Passing an alias reference (&). This is safe in Céu, scopes are considered, deterministic concurrency, blah, blah...
- Receiving back immediately an alias reference. This is tricky. I want a value that is created by the "code/await" and I need to interact with it safely, i.e., only while it exists.

I have to write about this second one, it is the biggest change in the language.
I'll only give an example here from "ceu-libuv":

var& _uv_tcp_t tcp;                                                            
event& void ok_connected;                                                      
watching UV_TCP_Connect("127.0.0.1",80) => (tcp, ok_connected) do   
    await ok_connected;
    ... // use "tcp" safely while connected
end

This is the example "tcp-06" and I consider it very readable:
https://github.com/fsantanna/ceu-libuv/blob/master/samples/tcp-06.ceu

We spawn a connection to localhost:80 ("UV_TCP_Connect" is a "code/await"): all connection process, disconnection, etc. is handled there.
I receive back a "tcp" handler and a local event from there immediately. They are "intermediate" return values and are alive while the call is alive.
This handler must be created immediately in the outermost scope of "UV_TCP_Connect" and this is statically checked.
Inside the "watching", I can safely use "tcp" and "ok_connected" although they are in the scope of the call.
If the connection is lost/etc, the code returns, the "watching" terminates, and "tcp" is unbound outside (this is also checked statically).
 
And does this mean that code/tight is basically for defining non-concurrent function?

Yes.
 

(also this really shows how confusing labels like "functional programming" and "imperative programming" are, because this looks like a happy fusion of the two)

I think this is a consequence of using existing English words to define precise CS/mathematical concepts.
The same thing is happening with "reactive" now.
I'm using "code/tight" and "code/await" to avoid confusion with "function". I also like "routine" or "procedure".
The problem is that function in English also means these things, even in the context of computation (e.g., F1--F12 are very imperative).
I chose "code" to be symmetric with "data", i.e., we provide data and code abstractions in Céu.
I'm also avoiding "reactive language" in favor of "structured synchronous language".

I'm liking the newly introduced notations a lot as well. At least I don't remember this one:

> loop i in [0->5[ do

My guess is "from 0 up to 5 (not including)", is that correct? If so, cool way of describing inclusive/exclusive ends! Never thought of using reversed brackets to represent open/closed ranges of math notation. The code/await syntax looks Maths-notation inspired (in a good way) as well.

Let's see if it works. People in my Lab had mixed feelings. ;)

One question. You never saw "]a,b[" to describe open ranges in programming languages or at all?
Here, I think this notation is more common than "(a,b)" and Wikipedia also seems to prefer it:
https://en.wikipedia.org/wiki/Interval_(mathematics)
 
Speaking of notation, is there a way around this amount of extra bookkeeping?

  var&? SDL_Rect rct1;
  event&? void col1;
  loop (rct1,col1) in birds do
    ..
  end

Wouldn't the types of rct1 and col1 already be known to the compiler, because it's a pool of Birds?

The problem is not the type here.
Inside the "loop", we have an "emit" which might awake something that kills the current bird being traversed.
The idea is to have safe loops that still allow using "emit", "spawn", and other yielding statements.
This was disallowed in previous versions.
 
Similarly, there's this:


    code/await Bird (var int y, var int speed)
                        => (var&? SDL_Rect rct, event&? void go_collided)
                            => void
    do
        var SDL_Rect rct_ = val SDL_Rect(20,y, 50,45);
        rct = &rct_;


Which feels like the kind of type accounting that the computer should be able to automate away for you, maybe like so:

    code/await Bird (var int y, var int speed)
                        => (var&? SDL_Rect rct, event&? void go_collided)
                            => void
    do
        rct = &val SDL_Rect(20,y, 50,45);

This is of course ignoring that things like type inference being a lot of work to implement, and I totally understand that you have to prioritise.

Yes, this could be automated. No problem with type inference though. It is only that the SDL_Rect needs real storage in "rct_" and "rct" is only an alias to something concrete (which could be anonymous).
 
How is overall performance (both size and speed wise) compared to v0.10?

Much worse in size.
Probably worse in speed.
Now, I favored simplicity in the implementation.
I used to favor memory because of the proposed scientific contributions, i.e., my thesis was an alternative to C in sensor networks. The quantitative evaluation was very important.
That said, this is mostly due to not checking what features the program uses and always compiling the complete runtime (i.e., no #ifdefs for the generated code).
 
Will there be Arduino builds soon?

For the Arduino, I'll have to bring these checks back for sure.
I plan to start porting the examples soon to see the real damage of the new implementation in constrained platforms.
 
Anyway, really excited about the release, I wish I could make time to just fool around with the language more :)

Thanks for the quick evaluation, it is really helpful.
 
--
Francisco

Job van der Zwan

unread,
Oct 7, 2016, 10:25:46 AM10/7/16
to The Programming Language Céu
On Friday, 7 October 2016 15:13:35 UTC+2, Francisco Sant'Anna wrote:
Thank you. Unfortunately, Github only marks contributions to the "master" branch.
The development has been continuous since the beginning. I now have a stable situation in an University (unless the State breaks, which is not completely unlikely). :)

Good to hear! Let's hope the university survives all the chaos of <current year>
 

- Receiving back immediately an alias reference. This is tricky. I want a value that is created by the "code/await" and I need to interact with it safely, i.e., only while it exists.

I have to write about this second one, it is the biggest change in the language.
I'll only give an example here from "ceu-libuv":

var& _uv_tcp_t tcp;                                                            
event& void ok_connected;                                                      
watching UV_TCP_Connect("127.0.0.1",80) => (tcp, ok_connected) do   
    await ok_connected;
    ... // use "tcp" safely while connected
end

This is the example "tcp-06" and I consider it very readable:
https://github.com/fsantanna/ceu-libuv/blob/master/samples/tcp-06.ceu

We spawn a connection to localhost:80 ("UV_TCP_Connect" is a "code/await"): all connection process, disconnection, etc. is handled there.
I receive back a "tcp" handler and a local event from there immediately. They are "intermediate" return values and are alive while the call is alive.
This handler must be created immediately in the outermost scope of "UV_TCP_Connect" and this is statically checked.
Inside the "watching", I can safely use "tcp" and "ok_connected" although they are in the scope of the call.
If the connection is lost/etc, the code returns, the "watching" terminates, and "tcp" is unbound outside (this is also checked statically).

Ah, I guess that explains the two arrows in code/await UV_TCP_Connect (var _char&& ip, var int port) => (var& _uv_tcp_t tcp, event& void ok) => int, which had confused me before?

Yeah, it's pretty readable. As it stands, only the many question/exclamation marks and ampersands make me wonder how one might design more elegant way of handling that, while still being explicit and in control (it also indirectly reminds me of Go's design choice to not repeat C's spiral rule mistake).
 
I'm using "code/tight" and "code/await" to avoid confusion with "function". I also like "routine" or "procedure"

That is the traditional usage of the terms, from Pascal and Algol, right? There's also the term continuation, which I've seen in academic contexts and Lisp/Scheme talks but nowhere else, and I'm still not sure what it means. But avoiding terms with too much baggage is probably a good idea, especially if that baggage involves multiple conflicting interpretations.

Let's see if it works. People in my Lab had mixed feelings. ;)

Well, I guess the range notation feels similar to like leaving an open parenthesis; programmers develop anxiety at the sight of that for good reasons ;).
 
One question. You never saw "]a,b[" to describe open ranges in programming languages or at all?
Here, I think this notation is more common than "(a,b)" and Wikipedia also seems to prefer it:
https://en.wikipedia.org/wiki/Interval_(mathematics)

Nope! Never seen it before! But this stackexchange answer leads me to think it's not that common in English-speaking countries (and the Netherlands is next to England, so follows most of its mathematical conventions) http://hsm.stackexchange.com/questions/142/why-is-american-and-french-notation-different-for-open-intervals-x-y-vs-x/193#193 

  var&? SDL_Rect rct1;
  event&? void col1;
  loop (rct1,col1) in birds do
    ..
  end 
Inside the "loop", we have an "emit" which might awake something that kills the current bird being traversed.
The idea is to have safe loops that still allow using "emit", "spawn", and other yielding statements.
This was disallowed in previous versions.
 
I'm probably a bit slow, but I don't quite follow why that requires declaring rct1 and col1 outside of the scope of the loop?

Yes, this could be automated. No problem with type inference though. It is only that the SDL_Rect needs real storage in "rct_" and "rct" is only an alias to something concrete (which could be anonymous).

Nice.
 
 
How is overall performance (both size and speed wise) compared to v0.10?

Much worse in size.
Probably worse in speed.
Now, I favored simplicity in the implementation. 
I used to favor memory because of the proposed scientific contributions, i.e., my thesis was an alternative to C in sensor networks. The quantitative evaluation was very important.
That said, this is mostly due to not checking what features the program uses and always compiling the complete runtime (i.e., no #ifdefs for the generated code).

So not "inescapably worse by design", just due to convenience for implementation/maintenance? I think that's a good approach, makes it easier to change things and develop the language; premature optimisation and all that.

I plan to start porting the examples soon to see the real damage of the new implementation in constrained platforms.

Looking forward to it :)

Francisco Sant'anna

unread,
Oct 7, 2016, 10:39:38 AM10/7/16
to ceu-...@googlegroups.com


On Fri, Oct 7, 2016 at 11:25 AM, Job van der Zwan <j.l.van...@gmail.com> wrote:
On Friday, 7 October 2016 15:13:35 UTC+2, Francisco Sant'Anna wrote:var& _uv_tcp_t tcp;                                                            
We spawn a connection to localhost:80 ("UV_TCP_Connect" is a "code/await"): all connection process, disconnection, etc. is handled there.
I receive back a "tcp" handler and a local event from there immediately. They are "intermediate" return values and are alive while the call is alive.
This handler must be created immediately in the outermost scope of "UV_TCP_Connect" and this is statically checked.
Inside the "watching", I can safely use "tcp" and "ok_connected" although they are in the scope of the call.
If the connection is lost/etc, the code returns, the "watching" terminates, and "tcp" is unbound outside (this is also checked statically).

Ah, I guess that explains the two arrows in code/await UV_TCP_Connect (var _char&& ip, var int port) => (var& _uv_tcp_t tcp, event& void ok) => int, which had confused me before?

Yes. The first is the intermediate return, the second is the final return.
 

One question. You never saw "]a,b[" to describe open ranges in programming languages or at all?
Here, I think this notation is more common than "(a,b)" and Wikipedia also seems to prefer it:
https://en.wikipedia.org/wiki/Interval_(mathematics)

Nope! Never seen it before! But this stackexchange answer leads me to think it's not that common in English-speaking countries (and the Netherlands is next to England, so follows most of its mathematical conventions) http://hsm.stackexchange.com/questions/142/why-is-american-and-french-notation-different-for-open-intervals-x-y-vs-x/193#193 

This is surprising.

  var&? SDL_Rect rct1;
  event&? void col1;
  loop (rct1,col1) in birds do
    ..
  end 
Inside the "loop", we have an "emit" which might awake something that kills the current bird being traversed.
The idea is to have safe loops that still allow using "emit", "spawn", and other yielding statements.
This was disallowed in previous versions.
 
I'm probably a bit slow, but I don't quite follow why that requires declaring rct1 and col1 outside of the scope of the loop?

I misunderstood your question. I was thinking you were asking about the "?", not about the declaration.
Yes, we could infer the types. The previous version did this. We removed due to inconsistency with other places where you need it.
I like local inference, but that demands a lot of work. :)
 
How is overall performance (both size and speed wise) compared to v0.10?

Much worse in size.
Probably worse in speed.
Now, I favored simplicity in the implementation. 
 
So not "inescapably worse by design", just due to convenience for implementation/maintenance? I think that's a good approach, makes it easier to change things and develop the language; premature optimisation and all that.

Exactly.

Francisco

Francisco Sant'anna

unread,
Oct 15, 2016, 5:12:37 PM10/15/16
to ceu-...@googlegroups.com
On Fri, Oct 7, 2016 at 7:48 AM, Job van der Zwan <j.l.van...@gmail.com> wrote:

How is overall performance (both size and speed wise) compared to v0.10? Will there be Arduino builds soon?

Just updated the "ceu-arduino/" repo.
It's using more ROM, but not much: the biggest example I had ("ship.ceu") went from 6K->7K (including the LCD library).
RAM is more or less the same.


Reply all
Reply to author
Forward
0 new messages