Settings

Theme

Ark – A modern systems programming language

ark-lang.org

57 points by felixangell 11 years ago · 54 comments

Reader

vardump 11 years ago

Could this be used for embedded development? Currently C is used pretty much universally for this purpose. While C is better than straight assembler, it seems to be very prone for bugs, especially when there are multiple developers and over time in maintenance phase.

Something safer is desperately needed for embedded firmware development. Lack of such a language is already affecting physical safety of end user devices.

Something that can run for example on a microwave oven, car engine control, digital thermometer and industrial machinery.

Maybe I'm missing some, but some of the most important wish list items I can think of right away:

- High readability, Golang-like "understandability"

- Anywhere between 1 - 256 kB of RAM, 2 - 1024 kB of program ROM.

- Must have C-like code density and performance, but a small loss is acceptable in exchange for better safety.

- Ability to implement IRQ service routines, etc. low level code.

- Array access, pointer and type safety.

- Debugging support... this is a tricky one.

- Migration assist from C code. Doesn't need to be perfect, just to assist where ever feasible.

- Would be very nice: Some language level support for duplicating and checking critical variables in memory. Like those for controlling servos etc. physical. To improve end user physical safety.

Targets should include at least, in order of importance:

- ARM thumb-2 (like Cortex M0)

- Altera NIOS 2 (must be possible to modify easily to target custom instructions)

- 8051

Various Atmel architectures, MIPS and OpenRISC would also be nice.

But I guess it comes down to LLVM support for those platforms.

  • dom96 11 years ago

    I think that Nim satisfies many of the items on your list. Have you taken a look at it?

    Specifically, it's a very good C replacement as it compiles to C. So you can easily run it on all of those embedded architectures.

    While I must admit that it leans towards using a GC for memory safety, you can disable it and use Nim as a more readable C easily. If you're brave you can attempt to use Nim's GC in embedded hardware too, it's very flexible.

    If you want statically guaranteed memory safety then do check out Rust, I'm assuming you already have though and dismissed it for some reason.

    • vardump 11 years ago

      Yeah, Nim is one of the languages I'm interested in.

      > Specifically, it's a very good C replacement as it compiles to C. So you can easily run it on all of those embedded architectures.

      Yes, this is indeed a huge plus for this application.

      >If you're brave you can attempt to use Nim's GC in embedded hardware too, it's very flexible.

      I'm not going to be that brave. :)

      > If you want statically guaranteed memory safety then do check out Rust, I'm assuming you already have though and dismissed it for some reason.

      Static guarantees are good, less code and checking at runtime. I haven't dismissed Rust in any way. One huge bonus point for Rust is that it has a major organization, Mozilla, behind it. Of course, the fact that Mozilla is primarily interested to develop a web browser can be a liability. In the future, Rust might take a path that's less suitable for embedded firmware.

  • minthd 11 years ago

    If you're willing to be stuck with a specific architecture(xcore by xmos) ,they offer their XC language and tools ,which are very good your requirements:

    a actor model like language for the xcore mcu. supports actors(paralell tasks with communication chnnels, pattern matching on "events", assigning actors to diffeent "cores"-hw threads, boundary checks on arrays, special pointers(aliased/restricted) with good error messages, type checking, mostly compatible with c(except pointers)

    Debugging is very good: Regular debugger, xScope - a virtual scope/logic-analyzer with access to internal states.XTA Timing analyzer - can determine(i think statically) the worse case timing between any 2 points in code. xScope and XTA might also work in simulation mode.

    This complements well with their architecture ,which basically allows real-time without jitter, and with very high accuracy/speed, through usage of multiple virtual cores.

    Very well fitted to industrial environment, and maybe they would be willing to add your request for memory duplication of variables , because it fits their niche.

jflatow 11 years ago

Not to be confused with Arc: http://arclanguage.org/

webkike 11 years ago

If all this is Rust with the syntax of go, aw heck that's all I ever wanted anyway.

  • kibwen 11 years ago

    Although some bits of syntax are reminiscent of Rust, semantically it's not Rust in the slightest:

    "Ark is not a garbage collected language, therefore when you allocate memory, you must free it after you are no longer using it. We felt that, as unsafe as it is to rely on the user to manage the memory being allocated, performance takes a higher precedence. Although garbage collection makes things fool-proof and removes a significant amount of workload from the user, it inhibits the performance we were going for."

    https://github.com/ark-lang/ark-docs/blob/master/REFERENCE.m...

    This is the usual false dichotomy that languages subscribe to, where they presume that manual and unsafe memory management is the only alternative to dynamic and safe memory management. But Rust's secret sauce is that memory management is static and safe, thanks to linear types and the borrow checker. Rust is still the only competitor in the space of zero-overhead memory-safe languages.

    • donuteaters 11 years ago

      I really wish Rust was as great as you advocates say, but that has not been my experience. For background: I've been following it for a while now. About a year or so ago, I dove it into with enthusiasm, but I got bit when the sigils went away, and so I backed off until the 1.0 release. After the 1.0 release, I figured it was ready so I spent another couple of weeks learning the new way of things and really hoping that it would be my replacement for C and C++. I really wanted Rust to be great.

      Unfortunately, it has lots of warts that have sent me crawling back to C++. Addressing the particular item you're talking about here, manually specifying lifetimes of objects is a cure that's worse than the disease. It's great when the compiler infers everything for you, but I'm never going to be able to explain the syntax or semantics of those ugly 'a marks to my coworkers who aren't interested in programming language theory.

      Anyways, I've been tempted to write a full blog post listing all of my Rust complaints, but I figured it's better to just quietly let you guys enjoy your thing. However, whenever I see these advocacy posts from you and the other Rust honchos, I can't help but scream a little bit inside. It's really not as good as it could've been.

      To be really specific: it's great that you got "zero-overhead memory-safety", but I can't even implement fundamental data structures without using unsafe blocks and lifetime annotations.

      • kibwen 11 years ago

        Don't hold back! :) Criticism helps us improve, as long as you can make it constructive and make at least a cursory effort to understand Rust's goals. As I've said elsewhere, if memory safety isn't a priority for your product then Rust may not be for you.

        As for the lifetime annotations, we could be extending lifetime elision to more places, including to struct definitions, if people come up with rules that are easy enough to understand. I'd probably be for it, but there are others who think that if you go too far toward removing lifetime annotations then you actually make programs more difficult to understand and the language harder to teach. But that was also the argument against our current lifetime elision rules, which are pretty fantastic in retrospect, so I'm not particularly swayed.

        • Jweb_Guru 11 years ago

          I hate our current lifetime elision rules, as do many people who have been using Rust for a while. There was an RFC (which was closed) to add some back. IMO, the rules largely exist for the sake of making short examples look less threatening, rather than because they actually make Rust more usable.

      • Tyr42 11 years ago

        I feel like the explicit lifetime annotations just move the invariants from the comments to the code. So I feel like it's a good thing to make explicit. I could be wrong as projects get larger though.

        Though I do feel a bit let out after reading http://cglab.ca/~abeinges/blah/turpl/_book/vec.html which implements Vec from scratch, as it's not super simple.

        But really, that would be impossible in Go, just as tricky in C++ (if you make it stl compatible), and impossible in implement generically without lots of void* stuff in C, so I guess I wasn't sure what I was expecting. It's a pain to implement fundamental data-structures I guess.

        Still, if you've got anything new to say, go ahead and say it.

      • pcwalton 11 years ago

        What, specifically, would you want to have Rust do instead regarding lifetimes?

        It sounds like you don't want memory safety without garbage collection, based on your last paragraph, and that's totally fine! My use cases aren't necessarily your use cases, and I don't want to claim that everyone who truly doesn't care about zero-overhead memory safety is wrong. But I think it's defensible that memory safety is an important feature for many projects (for example, the ones I work on) in 2015, even if it results in an additional learning curve. The disease we're trying to cure is a never-ending stream of security vulnerabilities and crashes in systems code, and none of the attempts to solve the problem that have existed so far have worked.

      • Nadya 11 years ago

        >Anyways, I've been tempted to write a full blog post listing all of my Rust complaints, but I figured it's better to just quietly let you guys enjoy your thing

        Please do. I'd love to hear your thoughts on issues.

      • Shorel 10 years ago

        What is your opinion of D?

        Do you think when the standard library is totally GC free it would be good for your use cases?

    • vardump 11 years ago

      Well, while I see the advantages of manual memory management as an embedded and kernel driver developer, one should understand manual memory allocation and freeing are very expensive and unpredictable operations. Very, very far from "zero overhead". There's usually no way you can afford to allocate memory while processing an interrupt request! It's simply too unpredictably slow. (Not to mention many synchronization mechanisms memory management usually requires, like mutexes, are simply not feasible at IRQ level. No process switching is possible, so a deadlock occurs.)

      But some GC schemes could be fast enough even from an IRQ handler, if memory allocation is just something simple like an atomic add to top of heap pointer. As long as non-interrupt level routines, potentially running on an another core, have enough time to clean up the garbage.

      Manual memory management seems to be at the end of its road when it comes to high core count systems, with tens or hundreds of CPU cores. Allocation and application side object lifetime synchronization and management will simply saturate any inter-core communication mechanism, limiting scalability. GC should be able to get around that limitation. At that scale, you could already dedicate one or more cores just for cleaning garbage.

      • vardump 11 years ago

        For those who still think manual memory management and especially malloc and free are fast, check glibc implementation.

        https://fossies.org/dox/glibc-2.21/malloc_8c_source.html#l02...

        Also see this benchmark between different, faster allocators: http://locklessinc.com/benchmarks_allocator.shtml

        The extra work doesn't end at allocation. When you actually implement a concurrent system, you'll usually end up having corner cases at object lifetime changes, which you need to synchronize. If the memory is only claimed when there are no more references to it, this extra synchronization step can be avoided. If you can't rely on this, you'll probably end up doing synchronization, such as (atomic) reference counting.

        Synchronization is very expensive and it can quickly become the performance bottleneck for the whole system. On modern X86, you can do 5-20k floating point operations during one contended atomic sync op. Reference count increase or decrease is one sync op. A simple mutex needs two of those.

        The more you have CPU cores, the more there will be synchronization (cache coherence) traffic broadcasted to all cores.

        Words like "JIT" and "GC" seem to cause knee-jerk reactions in some developers. Likewise for manual memory management. It's not so black and white. There'll always be trade-offs. I usually write low level (firmware and kernel driver) and high performance code. C/C++/SIMD. Code that might need to react under a microsecond.

        My message is just please be more open minded.

        Analyze where your code spends its execution time. You might be surprised how much of it is spent in things like C++ streams, xprintfs and memory allocation. Unfortunately inter-core synchronization is more insidious. It's not visible in benchmarks on small systems. Often you only start to see hints of this problem when actually running on more cores. Enough of them, and that's all your code is doing.

      • yoklov 11 years ago

        Sure, malloc/free are slow, but in realtime code (and probably embedded too, but I've never worked there) you allocate out of arena to get around that.

        Suddenly your memory allocation routine is a pointer addition, and you don't need garbage collection either. Deallocation is just as fast as well, it just happens in one block.

        It requires a bit of care in the code using it to not grow memory in an unbounded fashion, but this isn't really hard once you get used to it.

        • vardump 11 years ago

          > Suddenly your memory allocation routine is a pointer addition, and you don't need garbage collection either. Deallocation is just as fast as well, it just happens in one block.

          That's one of the techniques I apply. I have also some other tricks with different trade-offs up in my sleeve.

          This is primitive garbage collection. Because compaction / sweeping phase is simply discard all, no marking phase is required.

          Sometimes you get a lot of interrupts in a sequence, and if the lower priority code didn't have a chance to clean up the arena, you lose data.

          Interrupts can also occur at any point, unless you disable them. But you can't keep them disabled for very long. Maybe long enough that you check IRQ handler is not currently running on another core. If not, swap an arena pointer IRQ routine uses, enable interrupts again and start to process the previously pointed arena buffer.

          > It requires a bit of care in the code using it to not grow memory in an unbounded fashion, but this isn't really hard once you get used to it.

          This. The babysitting code and care you need for this technique.

    • zem 11 years ago

      > Rust is still the only competitor in the space of zero-overhead memory-safe languages.

      the only mainstream competitor, perhaps; ATS does a good job of it too [http://www.ats-lang.org/]

  • pcwalton 11 years ago

    It doesn't look like it's memory safe.

    • felixangellOP 11 years ago

      Unlike Rust, this is something we aren't focusing on. I just really like Rust, so we borrowed a lot of the syntax.

      • pcwalton 11 years ago

        Yup, and that's a totally legitimate decision IMHO. Best of luck with your project :)

  • exacube 11 years ago

    wait, you don't like putting your List<> inside your Arc<> inside your Cell<> ?? ;)

    • kibwen 11 years ago

      The whole point of smart pointer types like Arc and Cell is that they give you fine-grained control over the capabilities of your data. If you don't need such fine-grained control, then Rust probably isn't the language you're looking for. :)

    • pcwalton 11 years ago

      You need those for memory safety. It is very true that you don't need Rust's memory safety features, such as Arc and Cell, if you don't want memory safety, but it's also not a very interesting observation.

      • cwzwarich 11 years ago

        There are alternative mechanisms that do not use Cell but still provide safe mutation of pointer-free data. Cyclone had one, and IIRC Rust itself even had one before a type system simplification.

        • pcwalton 11 years ago

          Sure, and I'd be interested in exploring how those might be integrated into Rust in the future. Carving out subsets of pointer-free data seems pretty powerful.

          (It doesn't seem like the language in the OP is interested in memory safety though.)

    • rubiquity 11 years ago

      Nobody puts Baby in the Box<>.

protomyth 11 years ago

Here the example on the site:

  func main(): int {
      mut i := 0;

      for i < 5 {
          printf("i: %d\n", i);
          i = i + 1;
      }

      return 0;
  }
I'm really curious about 2 things: that for seems to really be a while. Why := in the declare and = in the assignment?
  • notduncansmith 11 years ago

    Perhaps the author was inspired by the Go language, as those are both Go-isms: Go's only loop is a for loop, and := tells the compiler to infer the variable type when initializing.

    In fact, this snippet is only a few deviations away from being valid Go code.

    • AYBABTME 11 years ago

      Their compiler is written in Go.

      See https://github.com/ark-lang/ark

      • warmwaffles 11 years ago

        You also need to remember that at one point Go's compiler was written in C, as with rust. It's all apart of the language evolution.

        • AYBABTME 11 years ago

          I'm not blaming them, just saying there's evidence the authors are quite familiar with Go. =P

    • michaelmior 11 years ago

      := isn't really stating to infer the type (although this happens) but a way to differentiate variable initialization with assignment. When using := the variable is created while = is just a regular assignment. Having these as separate operators prevents errors like this:

          foo := 3
          fooo = 4
      
      The second line is invalid because fooo does not exist.
    • fapjacks 11 years ago

      Indeed it is written in Go, after all.

  • felixangellOP 11 years ago

    Hi, for is basically a while loop yes. We haven't implemented ranges yet, so this is the example we chose since it works, and it's fairly concise to fit on the website.

    I chose `:=` and `=` mostly because of personal preference.

rubiquity 11 years ago

How long before someone releases another language "to fix all the dangerous parts of C" -- but the twist is that this language is just C but it forces you into a `git add --patch`-style menu that makes you double check all your usage of malloc and free every time you compile?

andrewchambers 11 years ago

I don't understand how a language can be a year old and have 3000 commits, but have so few tests in its implementation.

That is an instant red flag for me.

  • felixangellOP 11 years ago

    It started off as a side project by myself, I'm a student so I work on it every now and then, but I'm 17 so I have bigger things to prioritise like my education. The large commit count is due to a certain someone cough Vedant cough making several accounts and doubling the commit history when he re-authors his commits.

    The fact that it's a year old is because the language has changed loads in the past, since I considered it a side-project that I would just play around with. However, after I stuck to something, it gained a bit more popularity and people started to help me out with it. Now we have ported to Go, with a decent sized team working on it (when we can).

    • andrewchambers 11 years ago

      I recommend increasing the number of tests significantly, this is really important. A compiler is one of the easiest bits of software to test, so mastering good practice here will help you in the future.

      It is impressive if you are only 17! Keep it up.

    • vardump 11 years ago

      So you're just 17. Heh. I've been working in this field for more than your age.

      Keep up the good work, I can't wait with what you'll come up with later!

      Goes to write some more bug prone C-based device driver code...

qznc 11 years ago

A comparison with Rust would be nice.

  • trollsalad 11 years ago

    Looks like it's basically Rust without the ownership, borrow checking, and a few other things. Think of C/Go(?) with a rust syntax, and a few more higher level things like boundary checking, unicode support, etc (I'm aware Go has unicode support, I mean C).

    • markus2012 11 years ago

      Rust provides a good solution to C++ legacy cruft, complexity, undefined behavior, data races and provides some nice new language features like ADTs, traits, etc. I find it ties the language feature together with a beautiful and well thought out syntax.

      Still, because of tooling, direct C++ interop and familiarity we would have stuck with C++. The killer feature that elevates Rust above everything else - and made us switch - is the borrow checker.

      • kibwen 11 years ago

        Mind if I ask who "we" is? I love hearing feedback from groups of people using Rust from their own projects, and at the moment I'm especially interested in people using Rust for their jobs. Feel free to send me an email to the address in my profile if you'd like to continue this discussion without derailing this thread.

topkekz 11 years ago

>Our goal is to write a systems programming language that adopts many modern concepts and advancements in the field of compilers and language design over the past 43 years.

But they still kept = for assignent and the very ugly == for comparaison. Into the trash it goes.

  • felixangellOP 11 years ago

    I've never really found those a problem, I imagine this is more of a subjective thing.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection