Giter Club home page Giter Club logo

acton's People

Contributors

aagapi avatar ddjoh avatar destynova avatar mikael-degermark avatar mvmo avatar mzagozen avatar neonrust avatar nordlander avatar omahs avatar plajjan avatar sydow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

acton's Issues

Acton compilation & package structure

All the compilation output currently goes in the same directory, which is in the Acton system directory. After #43 we at least split up so that system builtin and shipped modules are in libActon.a whereas project related go in libActonProject.a, still, both are placed in the lib directory in the system directory.

We should split this up to make it possible to install Acton on a system outside of a users home directory, yet let the user compile an Acton project in their home directory.

Acton projects typically live in the users home directory and when compiled should produce output in the Acton project directory. This also makes it possible to have multiple Acton projects with potentially overlapping module names but without creating conflicts.

Today, an .acton file marks a directory as a module? Is this correct? It's a little weird to me - I think they're too far in, I think I would rather mark something an Acton project and then presume the remainder of the directory structure based on that, something along the lines of (where Acton.toml marks this as an Acton project, similar to Rust's Cargo which has a Cargo.toml):

my-acton-project/
├── Acton.toml
├── out
│   ├── bin
│   │   └── main
│   ├── lib
│   └── modules
└── src
    ├── foo
    │   └── bar.act
    └── main.act

in main.act we can then do

import foo.bar

and access the things. I'm not quite sure how to structure the compiled output, but I think it should go in my-acton-project at least. I put a out directory that more or less replicates the things we currently write to the acton system directory but in the project directory instead. Under it we can write a project local modules and lib. Did a POC patch (there is some debug output printed first, ignore... or not). It finds the project path based on the presence of a Acton.toml file there, then assumes src exists in there etc:

kll@ThinkYoga:~/kod/my-acton-project$ actonc --verbose src/foo/kaka/banan.act 
projPath: /home/kll/kod/my-acton-project
subdirs: src foo kaka
dirInSrc: foo kaka
fileBody: banan
srcPath: /home/kll/kod/my-acton-project/src/foo/kaka
## sysPath  : /home/kll/terastream/acton
## sysMod   : /home/kll/terastream/acton/modules
## sysLib   : /home/kll/terastream/acton/lib
## sysRoot  : /home/kll/terastream/acton/modules
## projPath : /home/kll/kod/my-acton-project
## projMod  : /home/kll/kod/my-acton-project/out/modules
## projLib  : /home/kll/kod/my-acton-project/out/lib
## srcRoot  : /home/kll/kod/my-acton-project/src
## modPrefix: foo
## topMod   : foo.kaka.banan
Compiling /home/kll/kod/my-acton-project/src/kaka/banan.act... Done.
kll@ThinkYoga:~/kod/my-acton-project$ 

In this case the Acton system is "installed" in /home/kll/terastream/acton (which we "find" based on the location of actonc, which I've included in my PATH). This should really be somewhere in /usr for a proper installed system - it is somewhere to which only root can write and not my user. Thus, we cannot write any output there. The builtin modules etc are in there though!

I found sysRoot confusing, like I have managed to learn that it is a subdirectory to sysPath (I sort of want to think the root is higher up) but then I can never remember whether sysRoot is the root of the lib files or the code (.c / .h / .ty)... so I propose we replace it with sysMod which is clearer, at least to me. Similarly we have sysLib for the lib directory. Since #43 we already put project library output in a separate libActonProject.a and libActon.a contains the system builtin / included libraries. Thus, for this we just need to change so we put libActonProject.a in projLib. When building we need to add (-L) both the projLib and sysLib directories to ensure we can find libActonProject.a and libActon.a. Cgen output goes in projMod instead of sysRoot / sysMod like now. We obviously need to include both when building so we can find the right .h and .ty files.

I'm not entirely sure about the meaning of topMod and modPrefix but I think I wrangled them right in my POC.

Changes

  • rename srcRoot to projPath
    • new projPath variable should have same value as old srcRoot
    • there will be a new srcRoot
  • add srcRoot variable = projPath ++ "/src"
  • rename --path argument to --syspath to further clarify what it is for
  • make sysPath default to a compile time value which depends on where we intend to install something for a particular platform
  • new sysLib is sysPath ++ /lib
  • new sysMod is sysPath ++ /modules
  • new projLib is projPath ++ /lib
  • new projMod is projPath ++ /modules

Acton system structure

I wrote above that the structure of the Acton system should be defined at compile time, like we define sysPath. On a Debian (like most Linuxes) this would prolly be /usr/lib/acton, so if we compute sysLib and sysMod based on that, we'd end up with like:

/usr/bin/actonc
/usr/lib/acton/lib/
/usr/lib/acton/modules/

It's a little weird to have a lib directory nested under our under /usr/lib/acton but they're sort of different libs, like this isn't the "compile any C library on your system with these lib files", so our lib is different. Yet, I do think the acton dir belongs in /usr/lib. There are many things in there that aren't C libraries we can link to and it seems our stuff belongs there. Alternative is like /usr/share but there's mostly other stuff in there?

I explicitly want to say that I don't think it's an option to place our libs in /usr/lib and our generated C code (.h header files) in /usr/include. If you only were to look at the type of file, like "this is a .h file" you might be tempted to put it in /usr/include but our files are not for generic C use - they are specific to Acton and thus do not belong there.

On FreeBSD I think the equivalent is:

/usr/local/bin/actonc
/usr/local/lib/acton/lib/
/usr/local/lib/acton/modules/

We notice that the paths relative to each other and actonc are actually the same, so it might be that we could keep the current approach of determining sysPath based on the location of actonc - just that we also assume a structure, specifically:

bin/actonc
lib/acton/lib/
lib/acton/modules/

so like

  • sysPath = joinPath [ takeDirectory $ takeDirectory execDir, "lib", "acton" ]
  • `sysLib = joinPath [ sysPath, "lib" ]
  • `sysMod = joinPath [ sysPath, "modules" ]

we could make this work in the acton source repo just by moving files around a bit, then it'd always be the same! Simple!? Or we just supply --syspath when invoked in the development repo...

Implement proper declarative Makefile

The current make targets aren't properly declarative. The offending targets are mostly those that add something to the libActon archive, like in rts/Makefile we find:

rts.o: rts.c rts.h
	cc $(CFLAGS) -g -Wno-int-to-void-pointer-cast \
		-pthread \
		-c -O3 rts.c
	ar cr ../lib/libActon.a rts.o
	cc $(CFLAGS) -c empty.c
	ar cr ../lib/libcomm.a empty.o
	ar cr ../lib/libdb.a empty.o
	ar cr ../lib/libdbclient.a empty.o

as can be seen, it writes to ../lib/libActon.a and other archives in ../lib/. A proper declarative target would instead define a target for how to build lib/libActon.a and have it depend on the constituent parts. This way out of date dependency calculation will actually work. Right now the only way to be safe is to do a make clean first and then recompile the whole shebang which is exceedingly annoying

Split libActon.a into acton part and locally compiled modules

When compiling Acton itself and the Acton RTS, libActon.a is produced. Later when we use actonc to compile programs written in Acton, it will place the resulting modules in the libActon.a archive, mixing up things that were delivered as part of Acton and what has been locally compiled. We should have a clear division of what is part of Acton and what has been locally compiled using Acton.

Add `random` module

Need some basic functions to get random integer in a range etc.

Must be thread safe though!

Let actonc deduce system path based on source file and a new? acton system configuration file

Proposal

actonc should automatically detect the acton system path based on:

  • the specified source file (the one we are asked to compile)
  • from the specified source file, traverse directory structure upwards to find an acton configuration
  • the acton config file is at the root of the system path, thus we have found system path

The configuration file can contain various project settings. I think this is sort of similar to how Rust's cargo works, e.g.:

$ cargo new my-project
     Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

when creating a new project, a top level project config file is generated (Cargo.toml) that contains project settings. Then there's a standardised project directory structure.

Motivation

actonc currently assumes its own location is at the root of the system. This requires a copy of actonc with every Acton project. This in itself isn't overly bad, roughly similar to a Python virtualenv with its own interpreted (got to guarantee not just library version but also the interpreter!). However, like Python virtualens are an optional thing, I think it should be optional for Acton. I imagine that after you've installed acton, the compiler will live in /usr/bin along with its required supportive infrastructure in /usr/lib/acton or so. That should be enough to compile Acton programs.

@nordlander and I have talked about this or at least adjacent topics before and he convinced me about certain points - at least he had thought more about the topic than I had, at the time. I believe the core concept @nordlander wants is to avoid "path hell", where the compiled output will vary based on what paths happen to be in the hypothetical "ACTON_PATH". It seems to me that this boils down to not having a PATH for searching for libraries etc. Instead we want a package tool that resolves libraries for us, downloading specific version as necessary etc. I agree with this, but I think it is largely orthogonal to the location of actonc. We should not need to have a copy of actonc in itself. We can still consider actonc a package that should be versioned, or rather than in the project config, we can specify a particular version of actonc to use... but I don't think that needs to mean that it has to live in the root of project directory.

Haskell stack uses a specific resolver to resolve what versions of packages to use etc. The resolver also dictates the haskell compiler version. Stack downloads stuff to /.stack - so it is possible to have multiple versions installed, but they are not installed per project but rather in a shared location. This seems like a sane design. To allow it for acton, we need to decouple the installed location of acton with the project directory.

This is relevant right now because I want to create some form of "release" of Acton that can be downloaded by users wanting to try it out. The shape and form of that release will need to look different depending on how this works.

Time limited await

I think it would be cool to be able to await an async message but give a time limit for how long we wait. Discuss!

Fix README.md getting started example

The README.md says to download Acton, extract and then run examples/helloworld... it's just that we don't include that in the release... so either include it or give different instructions?

Type error: Unable to solve type `Number` / `int` / `Times` / `RealFloat`

This program:

actor main(env):
    var foo = 1
    var bar = foo * 0.5

    def finish():
        env.exit(0)

    after foo: finish()

results in this compilation error:

******************** Type error
Cannot solve 'w$7' : 'T$5' (__builtin__.Number), 'w$12' : 'T$5' < 'T$9', 'T$5' < __builtin__.int, 'w$16' : 'T$9' (__builtin__.Times['T$11']), 'w$15' : 'T$13' < 'T$11', 'w$14' : 'T$13' (__builtin__.RealFloat)

It seems the compiler can't solve this where foo needs to be of type Times for the after: statement (I guess) and also being a float when assigning variable bar (since it multiplies by 0.5, which is a float). I can make it work by explicitly casting foo to a float in the assignment of bar:

actor main(env):
    var foo = 1
    var bar = float(foo) * 0.5

    def finish():
        env.exit(0)

    after foo: finish()

However, I think it should be possible to do this, i.e. cast foo to an int explicitly and then rely on the system understanding that an integer can be cast as a float and do that for me implicitly.

actor main(env):
    var foo = 1
    var bar = int(foo) * 0.5

    def finish():
        env.exit(0)

    after foo: finish()

It returns another unsolvable type error though:

******************** Type error
Cannot solve 'T$15' < __builtin__.int, 'w$16' : 'T$15' (__builtin__.RealFloat)

Basic live upgrade scenario

Here's a basic scenario for the live system upgrade. I think it can serve as an example for a discussion on the topic.

This is a simple program, version 1:

actor Counter(foo):
    var a = 0
    def get():
        a += 1
        return "%s: %d" % (foo, a)

actor main(env):
    var counter = Counter("banana")
    def _work():
        msg = counter.get()
        print(msg)
        after 1: _work()
    _work()

We decide to rename the variable a to b so that the program becomes:

actor Counter(foo):
    var b = 0
    def get():
        b += 1
        return "%s: %d" % (foo, b)

actor main(env):
    var counter = Counter("banana")
    def _work():
        msg = counter.get()
        print(msg)
        after 1: _work()
    _work()

We want the running program to be upgraded to the new version without losing its state. It is likely not possible to infer that the variable called b has the same purpose that the variable previously called a had, so mapping the old value in a to b becomes a manual upgrade task. The upgrade function could look like:

def upgrade(old, new):
    new.b = old.a
    return new

The upgrade function is handed two arguments, the first is the old actor instance and the second is the new actor instance, which has already been instantiated for us. We are expected to return the new actor instance. If there are parts of an upgrade (or the whole upgrade) that can be done automatically, then it is just a matter of returning new. In this case, something has automatically mapped the old variable foo to the new variable foo. If manual mapping are required, then that code needs to be filled in and... return new. It is naturally also possible to instantiate your own new actor instance. new is only provided through an argument as a matter of convenience - in fact, this way, we could have a default upgrade function that would run when none is manually built.

  • can we do type / sanity checking on an upgrade function? like can we detect if an upgrade function has missed upgrading some actor attributes?
  • how can an upgrade function access or write private actor attributes?
  • how can we upgrade an actor that has messages waiting? like if we always schedule a after X for ourselves or are just really busy?

Make `tip` releases available with a stable URL

Right now the tar balls available in https://github.com/actonlang/acton/releases/tag/tip include the version, like acton-darwin-x86_64-0.4.0.tar.bz2. This makes it impossible to get the latest tip release with a stable URL. It'll be even worse after #63.

I'm not sure if it is possible to alias / symlink, but given the (currently) small size of the acton system we can just upload it twice, so it is also available as acton-linux-x86_64.tar.bz2 - it is still possible to identify exactly which tip build it is using actonc --version.

This should make it possible to always get the latest tip by doing like wget https://github.com/actonlang/acton/releases/download/tip/acton-linux-x86_64.tar.bz2

Speed up RTS database startup

As discussed in meeting today; Investigate why acton programs take so long to start up with the database backend.

For example, try the simple count program we have: https://github.com/actonlang/acton/blob/main/examples/count.act

A description for how to run the database and program is in the header of that file!

The slow function is remote_read_full_table_in_txn at https://github.com/actonlang/acton/blob/main/rts/rts.c#L1329

Why is it slow on an empty (just started) system?

Why is it slow for a small system, like when we just have a single actor, shouldn't this run in "no time at all"?

Rename `__self__` to `self`

Is there a way to reference my own actor? Like self? If I give a callback to another actor I can just pass my method, but sometimes, like if the other actor should call multiple different callbacks, it could be easier to just pass a reference to my actor instead and have the other actor call methods on myself.

This is particularly difficult when we are the root actor, since we haven't created ourselves and thus do not have any handle on ourselves. For other actors there is at least a reference somewhere, like in the root. I suppose we could pass that reference to the actor itself so it would have a reference (stupid, but could work).

Move modules to modules/ directory

After the split of binary output now being written to the dist directory, we should place the source files of modules in the modules directory! At least for the simple modules where names align, like for time where there's a time.act, time.h and time.c. numpy is more complicated so I guess that one can remain as-is.

Allow `_` as variable name?

It is idiomatic Python to use _ as a dummy / throwaway variable. In Acton, it doesn't work:

kll@Boxy:~/terastream/acton/test$ ../actonc --root main pinger.act && ./pinger 

******************** Syntax error
pinger.act:25:11:
   |
25 |         _ = env.exit(1)
   |           ^^^
unexpected "= e"
expecting "def", ':', or comma

I tried to assign the return value from env.exit() as to get around #22 but trying to assign to _ fails with the above error. I don't think it should!? I'll classify as bug for now. If this is per design we can change classification.

Properly run some DB tests

I enabled a bunch of backend tests (I was really restructuring Makefiles) but didn't look much at the output... heh. Just saw this:

./actor_ring_tests_local
usage: ./actor_ring_tests_local <no_actors> <no_enqueues>
./actor_ring_tests_remote
usage: ./actor_ring_tests_remote <hostname> <port> <no_actors> <no_enqueues>

We obviously need to provide some sensible arguments here...

break not working in a for loop nested under a condition

This program fails

actor Thing():
    def foo():
        return 1

actor main(env):
    var thingies = [Thing()]

    for thing in thingies:
        bar = thing.foo()
        if 1 > 0:
            break

    env.exit(0)

like this:

kll@ThinkYoga:~/terastream/acton/test$ ../actonc --root main for-break.act
/home/kll/terastream/acton/modules/test/for-break.c: In function ‘test$_$for_45_break$$l$5c$7cont’:
/home/kll/terastream/acton/modules/test/for-break.c:126:9: error: break statement not within loop or switch
  126 |         break;
      |         ^~~~~
/usr/bin/ld: /tmp/ccyWB2dw.o: in function `$ROOTINIT':
/home/kll/terastream/acton/modules/test/for-break.root.c:3: undefined reference to `test$_$for_45_break$$__init__'
/usr/bin/ld: /tmp/ccyWB2dw.o: in function `$ROOT':
/home/kll/terastream/acton/modules/test/for-break.root.c:6: undefined reference to `test$_$for_45_break$$main$new'
collect2: error: ld returned 1 exit status
kll@ThinkYoga:~/terastream/acton/test$ 

I think something special happens when an actor is involved, like thing in our code. If we remove that or replace it with a simple variable assignment, everything works just fine:

actor Thing():
    def foo():
        return 1

actor main(env):
    var thingies = [Thing()]

    for thing in thingies:
        bar = "hello"
        if 1 > 0:
            break

    env.exit(0)
kll@ThinkYoga:~/terastream/acton/test$ ../actonc --root main for-break.act
kll@ThinkYoga:~/terastream/acton/test$ echo $?
0
kll@ThinkYoga:~/terastream/acton/test$

Similarly moving the break out of a condition works:

actor Thing():
    def foo():
        return 1

actor main(env):
    var thingies = [Thing()]

    for thing in thingies:
        bar = "hello"
        break

    env.exit(0)
kll@ThinkYoga:~/terastream/acton/test$ ../actonc --root main for-break.act
kll@ThinkYoga:~/terastream/acton/test$ echo $?
0
kll@ThinkYoga:~/terastream/acton/test$

Add performance benchmarks to CI

  • use haskell tasty thingy... there is some form of add-on for performance testing
  • basically want to run our normal test suite, or perhaps a subset, but repeatedly for perf measurements
  • unlikely that normal github public ci action runners will yield very consistent results
  • more likely we will need to run these jobs on dedicated runners that do nothing else
  • we should probably not run these jobs as part of PR pipeline but rather nightly on main branch

Add helloworld example

Just noticed that the example I reference in README.md in #59 is missing! Need to add examples/helloworld.act - it exists locally on my machine!

Fix `db_unit_tests` failures

We now run backend/db_unit_tests in CI but there's at least two problems. One test case is reported as failing, see below:

./db_unit_tests
Test create_schema - OK
Test populate_db - OK
Test test_search_pk - OK
Test test_search_pk_ck1 - OK
Test test_search_pk_ck1_ck2 - OK
Test test_search_column - OK
Test test_search_index - OK
Test test_update - OK
Test test_delete_col - OK
Test test_delete_pk_ck1_ck2 - OK
Test test_delete_pk_ck1 - OK
Test test_delete_pk - OK
Test repopulate_db - OK
Test test_delete_index - FAILED
Test test_range_search_pk_copy - OK
Test test_range_search_pk_ck1 - OK
Test test_range_search_pk_ck1_ck2 - OK
Test test_range_search_index - OK

However, this isn't reflected in the return code of the db_unit_tests program - it should exit with a non-0 exit code!

Also, the test_delete_index test should be fixed, or well, the code that test_delete_index is testing!

  • fix return code
  • fix actual bug so tests pass!

Event loop I/O plan

We currently support kqueue, which means the RTS works out of the box on BSDish platforms like OS X. On Linux, we use libkqueue, which is a compatibility shim so that programs written for kqueue can work on Linux (which is mapped to epoll on Linux).

What should be our ultimate plan? I think we have a few different options

  • natively support every platform
    • kqueue on BSD / Darwin
    • aio on Linux
    • Windows what?
    • something else?
  • use libuv or similar that in turn supports multiple platforms
    • this will definitely decrease our maintenance work and perhaps also the actual initial implementation work to quite a degree
    • we presume performance will be worse, in particular for the case of Linux and aio, which allows batching of operations not possible with any other interface
  • a hybrid of the above
    • aio on Linux for max performance - Linux is the likely most popular production load platform, so performance here matters

Without really knowing much of anything here, one hybrid choice appeals to me:

  • replace our current kqueue support with libuv
    • will this worsen our performance on BSD?
  • directly support aio / uring
    • this will support maximum performance on Linux
    • Linux is the likely main platform anyway
    • linux async io / uring offers better throughput than anything else, at least on paper, given command batching etc
      Alternatively, keep the kqueue support, so we use libuv for weird platforms (windows?)... that would mean supporting three interfaces (libuv, kqueue, aio)... is there even a point in trying to support windows? If so, then why not natively since we'd still get three APIs? Perhaps there's also the factor of the semantics, look and feel of those interfaces. If they are very different then it will be harder for us.

libuv supports many things, so it might be that certain operations could be implemented with less code using libuv while we use the native APIs for the operations where it really matters, i.e. in hot loops. For example:

  • async DNS resolution via libuv for cross platform support
  • kqueue & aio for socket operations, because they are heavily used and we get maximum performance using native APIs

Reading:

Run DDB test suite in CI

There are some tests in backend/ but they aren't called from any current make target. Make it so! The tests should be run in CI!

Variable not in scope under a for loop

Here's my program:

actor Foo():
    def ping():
        return "pong"

actor main(env):
    var actors = [Foo()]
    for act in actors:
        act.ping()
    env.exit(0)

Which results in this compilation error:

******************** Compilation error
 8:9-11
  |
8 |        act.ping()
  |        ^^^
Name act is not in scope

I can work around this by doing an assignment, like so:

actor Foo():
    def ping():
        return "pong"

actor main(env):
    var actors = [Foo()]
    for act in actors:
        a = act.ping()
    env.exit(0)

but I don't think that should be necessary. Another way is to wrap it in another local method:

actor Foo():
    def ping():
        return "pong"

actor main(env):
    var actors = [Foo()]
    def ping_actor(act):
        act.ping()
    for act in actors:
        ping_actor(act)
    env.exit(0)

Intermittent failures of queue_unit_tests

I don't know how to see old runs of a GitHub Action for a PR but for #82 I had two failures of a database related test and IIRC it was queue_unit_tests. We should try to reproduce somehow... I had to manually re-run the workflow twice to get it working, so I know something was failing. It was just failing under the Linux job and not on OS X but I'm not sure that has any real bearing, could just be intermittent!?

On the other hand, if we can't reproduce, then not sure what to do. So give this a shot I guess or give up and close issue.

Use `cc` instead of `gcc`?

actonc calls gcc. Should we change this to call cc instead? On Linux systems they are typically the same but I think on BSD platforms (not OS X), it could be something else?

`if is None` broken

I just added a very basic test to the repo in https://github.com/svallin/actwo/blob/master/test/ifisnone.act

For some reason, this code is fine:

    if f is not None:
        pass
    else:
        print("bad dice")

while trying to reverse the condition borks out:

    if f is None:
        print("bad dice")

error:

kll@mbp13:~/actwo$ make test
/Library/Developer/CommandLineTools/usr/bin/make -C test
/Library/Developer/CommandLineTools/usr/bin/make ifisnone
../actonc ifisnone.act
In file included from /Users/kll/actwo/modules/test/ifisnone.c:1:
/Users/kll/actwo/modules/test/ifisnone.h:9:42: error: unexpected type name '$Number': expected identifier
$R test$ifisnone$$l$1c$1cont ($Identity, $Number, test$ifisnone$$main, $Env, $Cont, $RFile);
                                         ^
/Users/kll/actwo/modules/test/ifisnone.h:9:51: error: unexpected type name 'test$ifisnone$$main': expected identifier
$R test$ifisnone$$l$1c$1cont ($Identity, $Number, test$ifisnone$$main, $Env, $Cont, $RFile);
                                                  ^
/Users/kll/actwo/modules/test/ifisnone.h:9:72: error: unexpected type name '$Env': expected identifier
$R test$ifisnone$$l$1c$1cont ($Identity, $Number, test$ifisnone$$main, $Env, $Cont, $RFile);
                                                                       ^
/Users/kll/actwo/modules/test/ifisnone.h:9:78: error: unexpected type name '$Cont': expected identifier
$R test$ifisnone$$l$1c$1cont ($Identity, $Number, test$ifisnone$$main, $Env, $Cont, $RFile);
                                                                             ^
/Users/kll/actwo/modules/test/ifisnone.h:9:85: error: unexpected type name '$RFile': expected identifier
$R test$ifisnone$$l$1c$1cont ($Identity, $Number, test$ifisnone$$main, $Env, $Cont, $RFile);
                                                                                    ^
/Users/kll/actwo/modules/test/ifisnone.h:9:31: error: a parameter list without types is only allowed in a function
      definition
$R test$ifisnone$$l$1c$1cont ($Identity, $Number, test$ifisnone$$main, $Env, $Cont, $RFile);
                              ^
/Users/kll/actwo/modules/test/ifisnone.h:14:54: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
    $NoneType (*__init__) (test$ifisnone$$l$2lambda, $Identity, $Number, test$ifisnone$$main, $Env, $Cont);
                                                     ^
/Users/kll/actwo/modules/test/ifisnone.h:23:5: error: unknown type name '$Identity'
    $Identity w$14;
    ^
/Users/kll/actwo/modules/test/ifisnone.h:54:66: error: unexpected type name '$Number': expected identifier
test$ifisnone$$l$2lambda test$ifisnone$$l$2lambda$new($Identity, $Number, test$ifisnone$$main, $Env, $Cont);
                                                                 ^
/Users/kll/actwo/modules/test/ifisnone.h:54:75: error: unexpected type name 'test$ifisnone$$main': expected identifier
test$ifisnone$$l$2lambda test$ifisnone$$l$2lambda$new($Identity, $Number, test$ifisnone$$main, $Env, $Cont);
                                                                          ^
/Users/kll/actwo/modules/test/ifisnone.h:54:96: error: unexpected type name '$Env': expected identifier
test$ifisnone$$l$2lambda test$ifisnone$$l$2lambda$new($Identity, $Number, test$ifisnone$$main, $Env, $Cont);
                                                                                               ^
/Users/kll/actwo/modules/test/ifisnone.h:54:102: error: unexpected type name '$Cont': expected identifier
test$ifisnone$$l$2lambda test$ifisnone$$l$2lambda$new($Identity, $Number, test$ifisnone$$main, $Env, $Cont);
                                                                                                     ^
/Users/kll/actwo/modules/test/ifisnone.h:54:55: error: a parameter list without types is only allowed in a function
      definition
test$ifisnone$$l$2lambda test$ifisnone$$l$2lambda$new($Identity, $Number, test$ifisnone$$main, $Env, $Cont);
                                                      ^
/Users/kll/actwo/modules/test/ifisnone.c:2:31: error: unknown type name '$Identity'
$R test$ifisnone$$l$1c$1cont ($Identity w$14, $Number w$26, test$ifisnone$$main __self__, $Env env, $Cont c$con...
                              ^
/Users/kll/actwo/modules/test/ifisnone.c:17:79: error: unknown type name '$Identity'
$NoneType test$ifisnone$$l$2lambda$__init__ (test$ifisnone$$l$2lambda p$self, $Identity w$14, $Number w$26, tes...
                                                                              ^
/Users/kll/actwo/modules/test/ifisnone.c:26:5: error: use of undeclared identifier '$Identity'
    $Identity w$14 = p$self->w$14;
    ^
/Users/kll/actwo/modules/test/ifisnone.c:31:38: error: use of undeclared identifier 'w$14'
    return test$ifisnone$$l$1c$1cont(w$14, w$26, __self__, env, c$cont, p$1);
                                     ^
/Users/kll/actwo/modules/test/ifisnone.c:56:55: error: unknown type name '$Identity'
test$ifisnone$$l$2lambda test$ifisnone$$l$2lambda$new($Identity p$1, $Number p$2, test$ifisnone$$main p$3, $En...
                                                      ^
/Users/kll/actwo/modules/test/ifisnone.c:67:5: error: use of undeclared identifier '$Identity'
    $Identity w$14 = (($Identity)$IdentityOpt$new());
    ^
/Users/kll/actwo/modules/test/ifisnone.c:68:106: error: use of undeclared identifier 'w$14'; did you mean 'w$26'?
    return $AWAIT(env->$class->openR(env, to$str("ifnotnone.act")), (($Cont)test$ifisnone$$l$2lambda$new(w$14, w$26...
                                                                                                         ^~~~
                                                                                                         w$26
/Users/kll/actwo/modules/test/ifisnone.c:66:13: note: 'w$26' declared here
    $Number w$26 = (($Number)$Integral$int$new());
            ^
1 warning and 19 errors generated.
kll@mbp13:~/actwo$ 

Create homebrew formula & tap?

We should make Acton available via homebrew. I think that means we provide a "cask" tap!!!

This makes sense once we've gotten #44 fixed. We can't have Acton installed somewhere and write the output of actonc to that acton system directory.

Create debian packages

I'd like to produce a debian package of the Acton system so it is even easier to install!

This probably only makes sense after #44

`actonc --version` complains over missing file argument

Code / what did you do

I tried to run:

actonc --version

Expected outcome

I expected to see the version information

Actual outcome

actonc complains about a missing FILE argument.

kll@ThinkYoga:~/terastream/acton$ ./actonc --version
Missing: FILE

Usage: actonc [--parse] [--kinds] [--types] [--sigs] [--norm] [--deact] [--cps] 
              [--llift] [--hgen] [--cgen] [--verbose] [--version] [--stub] 
              [--path TARGETDIR] [--root ARG] FILE
  Compile an Acton source file with recompilation of imported modules as needed
kll@ThinkYoga:~/terastream/acton$ 

It's because FILE is a mandatory argument and not optional, so this is perfectly natural.

It's funny that I added this --version argument and apparently I must have only tested by like appending --version to some existing command that already had the file specified. I cannot have tried just running actonc --version :P

Asynchronous `env.exit()` is undesirable!?

Hmm, so I was a little perplexed over how my program apparently did things after I called env.exit(0), which I suppose must be because it will run async since there is no assignment happening. Changing to

foo = env.exit(0)

fixes it by exiting immediately as I expected.

Is this good? We've talked about async before, what to do implicitly and what to do explicitly (i.e. require keywords). Not sure if there is something new to be said. Maybe just complete our documentation and move on ;)

Recreate tip release

The tip release is updated for every CI run on the main branch. We upload new assets / artifacts and update the release note. The release date however stays the same, ie it is set when the tip release is created - not when it is updated. This irks me because all the content is fresh and I want the date to reflect that. It also affects the order in which it appears on the release page and I think it should go at the top.

I think the only way to fix this is to simply remove the tip release and create it from the Github Action workflow we use.

Add emacs-mode for acton

We should implement a language server for Acton and build an emacs-mode in Emacs that makes use of it.

Depends on #190

Fix `queue_unit_tests` failure

We run ./queue_unit_tests in CI / as part of tests and it shows an error:

...
Test join_consumer_thread - OK (0)
Test join_consumer_replay_thread - OK (0)
Test enqueue - OK (0)
Test dequeue - OK (0)
Test read_head - OK (0)
Test consume - OK (0)
Test dequeue - OK (0)
Test read_head - OK (0)
Test dequeue - FAILED (0)
Test read_head_replay - OK (0)
BACKEND: Queue 0/0 deleted
Test delete_queue - OK (0)
  • fix return code of queue_unit_tests to reflect that individiual tests are failing
  • fix actual bug

Detect errors / return code in gcc compilation

actonc uses C as an intermediate representation. That means after we've done compiling an .act program to C we run gcc to compile C to a binary and then include than in a library file that we can finally link together to form a program.

Some Acton programs do not currently compile correctly. They are valid Acton syntax, so they will pass the first compilation step but gcc will barf and return some error. However, actonc doesn't honor that return code and continues anyway.

Here's an example application that fails in that way:

actor Thing():
    def foo():
        return 1

actor main(env):
    var thingies = [Thing()]

    for thing in thingies:
        bar = thing.foo()
        if 1 > 0:
            break

    env.exit(0)
kll@ThinkYoga:~/terastream/acton/test$ ../actonc --root main for-break.act
/home/kll/terastream/acton/modules/test/for-break.c: In function ‘test$_$for_45_break$$l$6c$5cont’:
/home/kll/terastream/acton/modules/test/for-break.c:190:9: error: break statement not within loop or switch
  190 |         break;
      |         ^~~~~
/usr/bin/ld: /tmp/cc5uOMTi.o: in function `$ROOTINIT':
/home/kll/terastream/acton/modules/test/for-break.root.c:3: undefined reference to `test$_$for_45_break$$__init__'
/usr/bin/ld: /tmp/cc5uOMTi.o: in function `$ROOT':
/home/kll/terastream/acton/modules/test/for-break.root.c:6: undefined reference to `test$_$for_45_break$$main$new'
collect2: error: ld returned 1 exit status
kll@ThinkYoga:~/terastream/acton/test$ echo $?
0
kll@ThinkYoga:~/terastream/acton/test$ 

The resulting behavior can give quite subtle errors. When developing acton programs and iterating on the code, I can first have a working program, let's say the above program first looked like this:

actor Thing():
    def foo():
        return 1

actor main(env):
    var thingies = [Thing()]

    for thing in thingies:
        bar = thing.foo()

    print("Hello")
    env.exit(0)

(i.e. no break statement nested under a condition)

This works correctly:

kll@ThinkYoga:~/terastream/acton/test$ ../actonc --root main foo.act && ./foo
Hello

Now let's add back the break:

actor Thing():
    def foo():
        return 1

actor main(env):
    var thingies = [Thing()]

    for thing in thingies:
        bar = thing.foo()

    print("Hello")
    env.exit(0)

recompiling & running yields:

kll@ThinkYoga:~/terastream/acton/test$ ../actonc --root main foo.act && ./foo
/home/kll/terastream/acton/modules/test/foo.c: In function ‘test$foo$$l$5c$7cont’:
/home/kll/terastream/acton/modules/test/foo.c:127:9: error: break statement not within loop or switch
  127 |         break;
      |         ^~~~~
Hello
kll@ThinkYoga:~/terastream/acton/test$

that is, the compilation fail... and correctly does not output the foo binary nor the library in libActon but as we get return code 0 we happily continue to run.

C lib wrapping: explain when something is sync vs async!

I believe the following is true:

  • modules with free functions (not in a class or actor) will always be synchronous
  • methods on classes are also always synchronous, since they are really instantiated within an actor and everything within an actor is always synchronous
  • modules that implement actors will default to the actor behaviour, which is that when an actor method is called without binding the return value, like foo.bar(), then it is called asynchronously, whereas if the return value is assigned, like a = foo.bar() then the actor method call is synchronous

@nordlander is the above true? Also realized while writing this, that this is not specific to when wrapping C libraries - this is the generic Acton sync behavior, but I guess it is somehow extra relevant to point out when implementing a library.

I know it is possible to explicitly do something async or sync by adding await / async keywords at the call site. Is it possible to change the sync/async behaviour by specifying something at the function definition? No, right? I think I've asked this before but have forgotten.

Should add this to the guide!

Add time function

I need a time function of some sort in order to build benchmarks for Acton. Sure, I can measure externally from Acton but it would be so much better with a timing function. We don't need to implement a complete datetime style module. I'm talking about like simple UNIX timestamps - as long as they have enough precision!

kll@ThinkYoga:~$ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> time.time()
1626764135.0713706
>>> time.time_ns()
1626764135940527153
>>> 

so maybe build a time module but only implement the time() or time_ns() function!?

I don't think there are any special Acton concerns here, like talking to an external system. If an actor is migrated between two different compute nodes, then calling time.time() might give surprising results in case the machines time aren't synced up. Like the clock going backwards... but I think that can already happen, right? No guarantee of monotonic time.

Add runtime configuration of distributed database backend for RTS

Since a while back we build the RTS and have a compile time option (WITH_BACKEND) for the RTS to enable the use of the distributed database (DDB). The address and port to use is hard coded to localhost:32000.

We need to make it runtime configuration whether the RTS should use the distributed database backend or not as well as what host and port to connect to.

With this change, we can entirely remove the WITH_BACKEND flag and just have run time flags. It will greatly simplify experimentation with the database backend, in particular since the idea is that we will make binary releases of Acton available, so recompiling with an extra build flag would be a lot of work compared to downloading a readily available release.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.