Clay: A new language for generic programming (based on LLVM)
tachyon.in
tachyon.in
http://www.reddit.com/r/programming/comments/ctmxx/the_clay_...
Your dispatch code now:
record Square {
side : Double;
}
record Circle {
radius : Double;
}
variant Shape = Square | Circle;
procedure show;
overload show(x:Square) { println("Square(", x.side, ")"); }
overload show(x:Circle) { println("Circle(", x.radius, ")"); }
My "Objectivizing": interface Shape {
abstract procedure show(self);
}
record Square : Shape {
side : Double;
show(self) { println("Square(", self.side, ")"); }
}
record Circle: Shape {
radius : Double;
show(self) { println("Circle(", self.radius, ")"); }
}
variant Shape = Square | Circle;
Here, "abstract" declaration in the parent would make the children's "show" automatically become an overload.
'self' is variable which would be automatically specialized to the containing record. I think the resulting code isn't excessively verbose.Interesting language features, as far as I can tell:
* Type inference
* First-class functions/closures (interesting compared to C++)
* Overloading is based on compile-time evaluation, with the possibility to have arbitrary values as type parameters, and is similar to predicate dispatch (you can dispatch using arbitrary conditions), with also the possibility to do runtime dispatch.
* Most of the functionality of the language is implemented in libraries, with a small kernel of built-ins.
Library functionality:
* the standard standard library: arrays, vectors, maps, algorithms, sequence abstractions etc.
* tuples, unions, variants
* lazy sequences (streams)
* reference-counting shared pointers (boost::shared_ptr)
* SIMD intrinsics and vectors using SIMD operations
* bindings to the C standard library of Unix and Win32 API
* Green threads, channels
Other:
* C binding generator based on CLang
It reminds me of clojure multimethods (http://clojure.org/multimethods). Can dispatch conditions in Clay be "arbitrary"? (in the example it is on the value of 'x', but can it be as complex as in Clojure multimethods?
min(a, b) {
if(a < b)
return a;
return b;
}
From what I understand, this function can accept two Int32s, or a Uint8 and a Float32, or basically any other combination of numeric types. Is a new function for each type combination generated? I don't think there's any way around this to some degree, but I'm curious if you've been able to do anything to ease the pain. procedure foo;
[T1,T2]
overload foo(a:T1, b:T2) {
// by default, convert both arguments
// to the type of first argument.
foo(T1(a), T1(b));
}
// the following overload specializes for the case
// when both arguments are of the same type.
[T]
overload foo(a:T, b:T) {
...
implement the logic here
...
}Quillpad itself predates Clay and hence doesn't use it.
An example from algorithms/introsort of how the syntax would look:
overload introSort(first, last)
if first != last
introSortLoop(first, last, log2(last-first)*2)
finalInsertionSort(first, last)
instead of overload introSort(first, last) {
if (first != last) {
introSortLoop(first, last, log2(last-first)*2);
finalInsertionSort(first, last);
}
}The Python philosophy is that everything is expressed clearly and concisely. Parens around conditionals are just restating information that is already apparent, as are semicolons between lines. Fluent readers actually learn to ignore these syntactic features unless they're debugging (since these useless tokens are a breeding ground for bugs).
Ask yourself: How often do you mentally match the opening and closing parens on a conditional? How often do you rely on semicolons to tell when you're looking at a new statement as opposed to just looking at the lines of code?
It's a matter of taste.
Do I prefer significant whitespace ala python/haskell?
Yes.
Does it matter? No.
Does it matter when you're discussing a programming language you've just now encountered for the first time and is rather new and has many novel things to contribute to the world?
Fuck no.
Like I said, it was a vacuous thing to say. There are far more important questions to ask like,
"Are the generics a space-time trade-off similar to C++ templates?"
"Can I use the type system to encapsulate and restrict behavior in powerful ways, allow me to create performant but safe code?"
"Can I make a beowulf cluster out of this?"
Any of those questions have more substance than, "hurr whitespace is bettar why didn't you do tghaaaasdfsdgsg"
Christ-sakes.
And no, the time-space tradeoff of the generics is not necessarily a better question than how readable the language is. That is a matter of taste. I will spend more time reading the code than I will worrying about the performance characteristics of generics or creating a Beowulf cluster, so caring about the common case is not exactly vacuous, even if it isn't the #1 most important thing.
Doesn't matter.
>Beowulf cluster
It was a fatuous comment designed to compare with the original fatuous comment.
>the time-space tradeoff of the generics is not necessarily a better question than how readable the language is. That is a matter of taste
No it's not. Taste is preference, whether or not a language is impossible to deploy with generics in an embedded environment has absolutely nothing to do with whining about syntax.
importance:
Semantics > syntax
I don't think I've seen sophistry and an obsession with the trivial on hackerne.ws like this in quite some time.You're complaining about the color of the bikeshed when real discussion and work is to be done concerning the semantics and structure of the language?
Your complaints seem to reflect an idea that only features and implementations matter, while user interface is fairly trivial. If you believe that, I think you might be interested in this: http://www.alistapart.com/articles/indefenseofeyecandy/
I'll just leave it at that.
As for why I decided to bring the syntax up when semantics are more important, it seems to me that if a language designer hasn’t thought about the syntax of a language and has just copied verbatim the syntax of Java/C, then they show a lack of attention to detail, and there is a greater probability that they will continue to show this lack of attention to detail when designing the rest of the language. Yes, I could read the whole semantics section of the language spec and evaluate it directly, but that takes more time than some people have when faced with yet another unproven language to consider learning or watching. I’m sure more people than me use syntax as a warning sign, so the syntax of a language is important if the designer doesn’t want to scare these people off.
Later, once you understand things, there are a few very rare times that it is legit to use it. Those few times can be handled without using it, though, and many programmers continue to avoid it out of habit or philosophy.
As for including it in his new language, it looks like it's basically C with some syntactical sugar. He didn't so much 'include' it as fail to remove it. He got it for free from C.
On the other hand Edsger Dijkstra thought that having goto's in the language complicated the analysis of loops and also the analysis of the flow of the program. Dijstra did a great deal of research on structured programming which nearly all programming languages support (loop design, if then statements etc...) Citations: http://en.wikipedia.org/wiki/Goto#cite_note-4
http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pd...
What is the syntax for pointers for example ?
record Point[T] {
x : T;
y : T;
}
updateViaPointer(ptr) {
ptr^.x += 1;
ptr^.y += 2;
}
test() {
var p = Point(10, 20); // type will be inferred as Point[Int]
updateViaPointer(&p);
}Sorry about the tone of this comment but I fail to see anything that would make me go 'yes, let's try this'.
Generic programming is something you can do in any language, and most of the (successful) ones out there are created with that goal in mind.
Can someone more in the know enlighten me as to why 'clay' is special in this respect?
That's not true.
Generic Programming is about writing re-usable code that is also very efficient. On the whole, it requires the following:
- Static types
- Overloading
- Type-parametric functions (templates)
- Type specialization.
Not all languages have these features.
Generic programming first took off with C++, when it introduced templates. But a few languages before and after C++ have supported generic programming: Ada, Haskell, D, etc.
edit: formatting.
It's a bit like saying you can't write functional code unless you use a functional language.
That's not to say you can't write C in a generic way, but "generic programming" means something specific to computer scientists and has certain prerequisites.
And you can't write functional code without a functional language, without building a functional language on top of your language (which may not even be possible, e.g. you can do functional-ish stuff in C because of function pointers. Without them, you'd be stuffed.)
You can write functional code in a "non functional language", if by functional language you mean "Haskell, ML or Scala". But you need certain features like function pointers to do it, and in that sense you do need a functional language. Same for generic programming - you need certain features.
You can't do that for example :
def make_adder(num_1):
def adder(num_2):
return num_1 + num 2
return adderThe venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."
Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
-- Anton van Straaten
As for functional programming someone just released a lisp for PHP. That doesn't mean it's the 'right' way to do stuff, but it can be done, and programming 'generically' was done for years before someone took the time to produce a language for it. I've written piles of code that would write programs (usually C) to avoid having to write the same kind of code with slight variations.
In the end all this stuff is Turing complete, so if you can do something in one language, by simple reasoning you can figure out that you can do that trick in any other by implementing a (subset of) the former.
Additionally, generic programming is a computer science concept, and those types tend to prefer static-typing for safety reasons. They're probably not strictly necessary if you ignore efficiency.
http://en.wikipedia.org/wiki/Generic_programming
See also: http://en.wikipedia.org/wiki/Type_polymorphism#Parametric_po...