Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Cello – Higher Level Programming in C (libcello.org)
291 points by denysonique on Dec 26, 2014 | hide | past | favorite | 65 comments


Author here. I always get asked two questions about libCello.

1. Why? 2. Is anyone using it for anything serious?

The second one is easiest to answer: no. And most people are suprised to hear that I probably wouldn't use it for anything serious either.

If you hadn't noticed from my github page I love C, and while I am also very interested in the things Cello adds such as duck typing and interfaces, and all the syntactic sugar that makes thing really nice and literate; it doesn't interest me enough to choose it over C. Additionally who is going to want to use my project if it uses this weird hacky C library! People are (for good reason) very suspect of dependancies.

That isn't to say I don't like programming in Cello. I'm almost definitely the person who has written the most in it and some things are just a joy to write in it, and look so clear and functional and algorithmic. At some point in the distant future when I find the time I really will attempt something serious such as a web framework. If that takes off we seriously can decide if it really is a good project (hur hur hur).

To be fair, "why" can also be pretty easy to answer depending on who is asking: because I could. Because I thought it was kinda cool and that people would be interested. There seems to be some default position in programming that unless your project is silly or sarcastic people assume you are "advocating" something by doing it, or making some kind of political statement on software development. I didn't work on this project to try and change the world. Nor to create something better than the alternatives. It doesn't change my life if people use Cello or not. I wasn't frustrated with C++, and I wasn't looking for a cylindrical rolly thing for my cart. I just made it for fun.


It looks really good and you should be proud of your work.


Well coming from an industry c programmer (embedded, networking, high throughput stuff, where c is the only choice), i am really thinking this could be of a great use. Specially for large products developed and maintained for many years and have big teams, this could be priceless if actually ported / extended. I would probably look at this and try to contribute when i can. Thank you so much, great work


> it doesn't interest me enough to choose it over C.

Why? If it's as fast as C but has the benefit of sugar, why not use it?

> People are (for good reason) very suspect of dependancies.

Not web developers. :D Although we should be.

> And most people are suprised to hear that I probably wouldn't use it for anything serious either.

Again, why not? C performance but easier to read code sounds like a good reason to use it for something serious. What are the downsides?


It is not as fast as normally written C due to the dynamic typing.


that's not necessary for the API, is it?


The API allows 'var's to be treated as dynamically typed, so sure it is. More to the point, if you tried to change it to be statically typed, it wouldn't be expressible in the same nice-looking way in C.


I've seen similar retorts to explorations of functional or unconventional concepts in C, mainly because the usual approaches work well enough.


Previous discussion: https://news.ycombinator.com/item?id=6047576

This has tons of sugar; if you're just interested in how this stuff is possible in C it would probably be more instructive to look at the GNU library libffcall[0] which implements trampolines. The code is simpler and there's less syntactic sugar obscuring what's going on. Of course, the linked articles on the Cello home page are instructive too.

I've yet to actually use Cello myself since I feel like if you hack C up that much, you might as well just use something like C++, C#, Rust or what have you and gain even more benefits, like a mature ecosystem that's highly compatible with the features you're using while I worry Cello, when relying on normal C libraries, might require you to slip back into some C-isms that Cello desires to avoid due to your dependencies not caring.

[0]: https://www.gnu.org/software/libffcall/


> I've yet to actually use Cello myself since I feel like if you hack C up that much, you might as well just use something like C++, C#, Rust ....

Since the early 90's I never understood why some programmers insist in using what is basically a portable macro assembler for higher level programming.

It was already primitive when compared with the likes of Modula-2 and Turbo/Apple Pascal, not to mention all the other alternatives even higher level.


In general, because those languages essentially declared things were 'bad' that aren't bad at all. Sometimes you have to mung data. Pull it in off a serial bus, strip out the header, rearrange it for the next thing you are sending it to, and so on. Other times you really do need/want some kind of dynamic dispatch or duck typing. You can do that with void* and function pointers. Ugly, yes, and error prone to boot, but possible. These days hardware is a lot faster. Back then I was writing my own graphics implementations because Windows GDI was way too slow for what I was trying to do. Just for a pretty ordinary app. Today, I am still concerned with how my data lies on the CPU cache. I need to access cards with C api's. It is nice to think about things like rust, but in my current company we have 2 decades worth of C&C++ code. It works with everything; we know that if a new card comes out it will come with a C API, we know that we can hire C programmers. The debuggers are astonishingly good (seriously; compare Visual Studio's debugger to thrashing around with some open source debugger for some other language. It's a production language, for professionals, to get shit done. It's not going anywhere for a long, long time.

Not putting down the other languages - I use Python whenever I can, as it is such a joy to use. Anything other than C/C++ for most of my production code? Not in the foreseeable future.

If you feel the urge to quibble about that last sentence, recall how much existing code I (and by extension, the world) already have. Never, ever, can we afford to throw that away. Shall we write some horror show of Haskell, Erlang, Javascript, and Clojure interfacing into 'legacy' code that in fact would need to be updated all the time? No thanks. For all the hand wringing about memory management, between smart pointers (rolled my own before there were library versions) and RAII I can't remember the last time I spent a serious amount of time chasing down a resource leak. Maybe early 90's? I dunno, but it seems that I spend more time debugging Python code where I am passing in a variable of the wrong type and Python just silently spits out the wrong thing in response.

Would I like a 'better' language than C? Absolutely! Do I see one in my future? Not really. Because it is actually awesome at doing the kinds of things that need to be done.


Wasn't there some issue with Pascal type system being too restricting sometimes (the unfortunate lack of cast) ?


It wasn't just the lack of a cast. (IIRC, you could work around that with variant records if you really had to, though it was really clumsy.)

Another, unfixable problem was that the size of an array was part of the type of the array. This meant that you couldn't ever access past the end of an array, which was good. It also meant that you could never have a variable-sized array - you couldn't even talk about the type of such a thing.

This meant that Pascal was completely unusable for writing, say, a memory manager (what type would you give to the return from an allocation)? But that's a low level problem. It also meant that Pascal couldn't be used for a numeric simulation where the size of your grid was a user-supplied runtime value.

Note that I am only talking about the original (Wirth/UCSD) Pascal. I believe that Turbo Pascal fixed the variable-sized array problem.


Those problems were not part of the Pascal dialects.

The largely ignored Extended Pascal ISO standard also had those issues fixed.

The first Mac OS versions were written in Apple Pascal.


I knew about Apple programs being in Pascal, but the whole OS ? did they resort to inline asm ?


Yes, they did use Assembly.

When implementing an OS avoiding Assembly is impossible. Even if intrisics are used instead, they are just another way of using Assembly like instructions.

There are lots of informations in this book, "Revolution in The Valley: The Insanely Great Story of How the Mac Was Made".


They used more than some assembly. Andy Hertzfeld:

"But most of the Lisa code was written in the Pascal programming language. Since the Macintosh had much tighter memory constraints, we needed to write most of our system-oriented code in the most efficient way possible, using the native language of the processor, 68000 assembly language. Even so, we could still use Lisa code by hand translating the Pascal into assembly language.

"We directly incorporated Quickdraw, Bill Atkinson's amazing bit-mapped graphics package, since it was already written mostly in assembly language. We also used the Lisa window and menu managers, which we recoded in assembly language from Bill's original Pascal, reducing the code size by a factor of two or so. Bill's lovely Pascal code was a model of clarity, so that was relatively easy to accomplish."

Also, about half the LOC in MacPaint were assembly.


Basic, Forth, C and Pascal were the Ruby and Python of the 80's home computers, both in compiler code quality and memory usage.

Of course anything related to graphics programming would be written in pure Assembly code, so excuse me if I misused "Some".


Yes indeed, I forgot about that. I wonder if there ever was a purely 'compiled' OS from some declarative form.


You're probably remembering something from Brian Kernighan's 1981 essay, "Why Pascal Is Not My Favorite Programming Language". Lack of unsafe typecasts, as well as (I think) all of Kernighan's other main points in that essay were cured in Pascal implementations by end of the 80's. But by that time C had captured all the mindshare.


No, that was a problem only with the original Pascal as designed by Niklaus Wirth for teaching purposes.

None of the Pascal dialects that extended it with features for professional programming suffered from it.


Large parts of my undergraduate curriculum in the early 90s (at a mid-size well-funded public school in the united states) used pascal, and the unix and vms compilers we used most certainly suffered from the 'different array sizes are different types' issue.


I really love this. Are there convenience functions to convert existing values to and from your new data types?

I would love to use this library but as C programs often requires third-party libraries I could see many instances of having to use normal C types. Is there a way, for example, to easily convert a float to and from a var (with a Real key/value)? How would I use your library to take hash table values and assign them back into standard struct members? Would I just use traditional casting? Something tells me normal casting is not an option, or at least not so easy.


Converting a C value to a Cello value is easy.

  int cValue = 5;  // because I randomly feel like that's a good number
  var celloValue = $(Int, cValue);  // I'm pretty sure this works, but I haven't proven it
Coming back from Cello to C, it appears that you can do this:

  long anotherCValue = as_long(celloValue);


I see lots of weird comparisons here.

I think the most apt would be a comparison to Vala, which is compiled to C and also adds higher level languages features.

That said, Vala is much heavier, and requires manual writing of interface files to use C libraries.

I can see this being a useful tool if kept lightweight. It's certainly prettier than GObjects!


Has the development moved away from github[1] or has it completely stalled ? The last commit I see is from 8 months ago.

[1] https://github.com/orangeduck/libCello/


> To compile Cello requires a C99 compatible C compiler.

In fact, it fails to compile with -std=c99, it seems to require GNU extenstions, that's why they have -std=gnu99 in their Makefile. They use ##__VA_ARGS__, which is not in the C99 and AFAIK there is no portable way to make a workaround.


You're completely right, this definitely uses GNU extensions.

A note about the __VA_ARGS__ detail - You can portably avoid it in a lot of cases if you plan ahead and allow __VA_ARGS__ to suck-up one extra always-provided argument, but it's not as clean as the GNU extension and can't always be done.


Also looks like it uses nested functions.


Too high level IMHO... $(Int,5) is not reasonable, also everything is too opaque for it to be a C library. You can go a long way without creating such a layer of abstraction with just a set of libs implementing data structures, dynamic strings, with simple object-alike structures that are reference counted so that it is trivial to have lists of hashes or alike, but where you can also store raw stuff trivially just changing the "method" to free or dup the objects.

EDIT: AFAIK "$" is not valid ANSI-C, however I would love it... For example in a reference counting system could be cool to have $() and _() to incr/decr references.


The syntax is rather reminiscent of jQuery... and just like how that has created jQuery developers who know next to no JavaScript, I could envision many Cello developers who know almost no C which given the characteristics of the language would probably be an even bigger problem. It's good that they have a disclaimer saying that this isn't for those who don't already know C.

I think it's more like a framework than a library, based solely on the principle that it basically encourages a completely different syntax and code style that someone else would have to learn in addition to C in order to work with code written using it.


I'd say it's more reminiscent of Python, sans the dollar signs.

I feel that calling it a framework is really pushing it. C is such a simple language, and things like the GNU C extensions and the macros the Linux kernel provide offer some similar semantics, particularly when dealing with linear data structures. Not to mention, when dealing with POSIX, your coding style completely changes to fit what it gives you.


C is a simple language if you ignore all the traps, pitfalls, gotcha's, corner cases, and exceptions to the rules.

By that measure, maybe Brainfuck is a simple language too. But I wouldn't want to actually program in it when there are so many sane alternatives available.


> C is a simple language if you ignore all the traps, pitfalls, gotcha's, corner cases, and exceptions to the rules.

Yes, and no. If you're sticking with just raw C and the standard libraries, it's a simple language. That doesn't mean your program will be simple, however - security concerns alone ramp up the complexity by orders of magnitude. But at its core, it is a simple language with mostly simple rules.


C is a simple language when you compare it to C++. Especially if you need nailed down standards-compliant behavior.


bf would actually be easily bareable, if it had textual macros, include/packaging and standard defines, like C does.


It would be very interesting to pair this with a very well designed minimalistic web framework, drivers for things like Redis, etc., for some VERY high-performance web backends.


Let C be C. For the people who don't like C for one reason or another, there are a ton of alternatives available, from x64/x86 targeting languages to manages stacks. Adding these libraries to C might look nice, but if you want to experience the things it brings to the table use a language where it's been borrowed from.


I agree and don't agree. This is what I think too if you look at libs like Cello, this is almost an attempt to write a new language on top of C, in some way. It is an interesting experiment, but it can only end writing a compiler IMHO, turning what is sugar here into a real grammar emitting efficient code and so forth.

But, C can be improved a lot without violating its nature with better libs. Libc is very unreasonable on what it offers. It should have data structures, dynamic strings, a few buffers that are easy to consume both sides, and so forth. This is what people keep reimplementing again and again and again.


I agree with your argument that C has some bad parts which are desperately in need to be made better, but IMHO it should just stop there. Question of course then is: where is the line where it ends being updating bad parts of C and beginning to become a layer on top of C :) History has taught us that's sadly in the eye of the beholder .


I wrote cmacro[0] and magma[1] with the goal of a augmenting C while keeping it C-like.

[0]: https://github.com/eudoxia0/cmacro [1]: https://github.com/eudoxia0/magma


And I wrote Myrddin[0] for the goal of seeing what C would be if I was reimagining it with the benefit of hindsight.

[0]http://eigenstate.org/myrddin


This is beautiful.


After seeing this I started work on a simplification of libCello called Viola [0]. It has a slightly lighter syntax and takes away some (IMO) needless typing...

    [0] https://github.com/eatonphil/Viola


How are you implementing the dynamic type interface? Discriminated union?


It uses raw pointers (void*) and something a little like a vtable: http://libcello.org/documentation/hacking


I'd love to know how this compares to GoLang... Conceptually similar, which is faster?


I don't know that I would call it conceptually similar to Go. At least, not if we're looking at the Big Pictures concepts, where Go has concurrency as one of its major departures from C. I don't see any mention of concurrency primitives in Cello (maybe they're there and I didn't notice, but I would think the author would have put that on the front page, if it were a thing Cello tried to solve).

Go does provide collections and iterators and such, so Cello is similar on that front. But, every modern language provide those things, and Cello collections don't seem any more Go-like than they seem Python or ObjC like.

Well written C is consistently faster than well-written Go. There are some dynamic runtime elements to Cello that could potentially hurt performance but I doubt it's a major factor.

I think Rust is probably the better modern language to compare Cello to, and I suspect they'll have similar performance. ObjC would also be a reasonable thing to compare.

But, for most things, they're all Fast Enough. Performance is probably not a useful metric. The reason I could see for using this would be modernizing an existing C codebase (though I'd be cautious about relying on something like this until it has a healthy uptake among developers), or when working in environments where only C compilers and libraries are available. If I were starting a new systems project, I would start with Rust or Go (or maybe ObjC if I ever had to work on Mac/iOS).

Mostly though, I think it's just a cool experiment, and educational.


Nim, with its Pythonic syntax and native code generation via C, compares as well [1].

http://goran.krampe.se/2014/10/20/i-missed-nim/


TY!


I would assume one of the cello creators / advocates is down voting my posts so I'm bowing out of this thread. I asked a real question that clearly upset people for some reason.


I downvoted your "+1" and "TY" comments because they add nothing to the discussion -- just upvote instead of leaving such comments, this isn't Reddit (yet). Complaining about downvotes is also a good way to get more downvotes. Your original comment was probably downvoted since it's not very constructive either, it's just a random thought that entered your head (it's not a terrible thought, performance is something to be considered if you're seriously going to look over the pragmatics of using a random language), and it didn't really deserve to be a comment. A better comment that would have received upvotes would have been to run your own benchmarks and report the result instead of pointlessly wondering in public. (Or as the question can come across, demanding someone to do the benchmarking for you as presumably you searched for one before making such a demand.)


I'm actually very curious... I have a few project in golang and if this was more performant I would consider porting them.


Which, I think, misses the point. Unless your Go program is currently not fast enough, why would you consider a port? And, if it isn't fast enough, are you sure you are using the appropriate algorithms and tools for the job? It may be that Go isn't the right language, but I would think long and hard before a re-write from any language to any language, unless it's a toy project (in size, not importance), in which case, you could rewrite it and find out in a day or two and it might be a fun experiment worth writing about.

And, lots of benchmarks between C and Go have already been done. Likewise, Rust and Go, and Rust and C.


I agree with your comments 100%. Not sure why my comment got down voted but I would just like to see some benchmarks... Rust would be another interesting benchmark.


Just use C++11


Why does this exist?

(Serious question)


Because someone cared enough to make it.

(Serious answer.)

But I think you're really asking a different question than the one your words say. I suspect you're asking why someone should bother to write this. There are several possible reasons. "Just because they felt like it" is a perfectly fine reason. "Because they thought it was interesting" is pretty close to the same reason. "Because they thought the world needed this language" is probably not as good a reason, because it seems somewhat unlikely to be correct.


The last part might not be true. Though i won't generalize, let's just say that i have been writing industry code for almost a decade, 90% C (because of domain) and at least a quick review tells me, porting this to a couple of major platforms could be very practical and useful IF IF, it does not sacrifice the performance.


Why has this been posted multiple times? Seems like any opposition (healthy) gets down voted...


The author answered, and it's hovering at the top of the comments.


To scratch the itch, obviously.


+1


> /* Heap objects destroyed with "delete" */

> delete(items);

This part is funny: "Higher Level" but still no garbage collection.


Why would higher level necessarily imply garbage collection?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: