It was a little over two years ago that I saw Chris give a tech talk on LLVM at Google, and that was when I knew that there was a way that I could actually build the programming language that I'd been thinking about for so long. Well, the compiler is still not done, even though I've been plugging steadily away at it in my free time. However, a lot of progress has been made recently, and I thought perhaps some folks might be interested in what I am trying to do. The language is called "Tart", and the one-sentence description is "Tart is to C++ as Python is to Perl". Rather than go on about the philosophy of the language, however, I will show some code samples. For example, here's what the "Iterator" interface looks like: interface Iterator[%T] { def next -> T or void; } '%T' introduces a template parameter named T. The reason for the '%' prefix is to support partial specialization - you can mix template parameters and regular type expressions in the template argument list, as in "Iterator[List[%T]]". This is different from C++ where the template parameters and the specialization arguments are in separate lists. Like C++, Tart is a statically-typed language. Unlike C++, however, Tart's type solver can deduce the template parameters of a class from the arguments to the constructor or a static method. So for example, a factory function such as Array.of(1, 2, 3) can deduce that we want an integer array since the arguments are integers. Of course, we can always be explicit and say Array[int].of(1, 2, 3). Tart's type solver also allows function template arguments to be inferred based on the type of variable that the function's return value is assigned to. (Java does this as well). Thus, if you have some function that takes a set of Strings, you can say "myFunction(EmptySet())", and not have to explicitly specify a template argument to EmptySet - it knows what kind of set you want. Back to the example, the result of the iterator's 'next' method is a disjoint type (also called a discriminated union) written as "T or void". That is, it returns T as long as there are elements in the sequence, after which it returns void, i.e. nothing. LLVM's ability to efficiently return small aggregate types is critical to making this perform well. Ideally, the Tart iterator protocol ought to be faster than either Java Enumerators (which requires two icalls per loop, one for hasNext() and one for next()), or Python's iterators (which depend on exceptions to signal the end of the sequence.) To use the iterator interface, you can use the convenient "for .. in" syntax, similar to Python. Here's a snippet from one of my unit tests: def sum(nums:int...) -> int { var sum = 0; for i in nums { sum += i; } return sum; } The 'sum' function takes a variable number of ints (The ... signals a varargs function), and returns an int. The 'var' keyword declares a variable ('let', by contrast declares a constant, which can be local, similar to Java's 'final'). In this case, the type is omitted (you could say "var sum:int = 0" if you wanted to be explicit.) You could also write this out longhand: def sum(nums:int...) -> int { var sum = 0; let iter = nums.iterate(); repeat { classify iter.next() { as i:int { sum += i; } else { break; } } } return sum; } Since the iter assignment never changes, we can use 'let' to bind it immutably to the variable. 'repeat' is an infinite loop, essentially the same as writing "while true". 'classify' is like a switch statement, except that the cases are types rather than values. It works with both disjoint types and polymorphic types, similar to what is seen in Scala and various functional languages such as OCaml. The variables in the individual 'as' clauses are never in scope unless the assignment to that variable actually succeeds, so there's no chance of seeing an uninitialized variable. In any case, I don't want to go on about this too long - at least not until the compiler is in better shape to be shown to the world. I still need to work on closures, reflection, garbage collection, interface proxies, stack dumps, debug info, and a bunch of other stuff. (There's a Google code project for it, but I'm not encouraging people to go there until I have more of the language finished.) -- Talin
2009/9/15 Talin <talin at acm.org>:> For example, here's what the "Iterator" interface looks like: > > interface Iterator[%T] { > def next -> T or void; > }So this would be something like: template <class T> virtual class Iterator { T next(); // or void? }; So the power of having two types of return parameters is that you save function calls (hasNext())?> def sum(nums:int...) -> int { > var sum = 0; > for i in nums { > sum += i; > } > return sum; > }I see you don't have types for variables, only for containers, templates and functions. And yet you say your language is statically-typed. If you do: var foo = 10; // I'd presume it's an int foo /= 3; Would foo become a float? foo /= 1e200; Would it become a double? What happens if you pass foo as an int, and inside the function it becomes a double (without your consent, by a combination of parameters) and you try to return it as an int?> 'classify' is like a switch statement, except that the cases are types > rather than values. It works with both disjoint types and polymorphic > types, similar to what is seen in Scala and various functional languages > such as OCaml. The variables in the individual 'as' clauses are never in > scope unless the assignment to that variable actually succeeds, so > there's no chance of seeing an uninitialized variable.Is it run-time or compile-time? The former is Java's insanceof/C++ RTTI, the later has not many uses...> In any case, I don't want to go on about this too long - at least not > until the compiler is in better shape to be shown to the world. I still > need to work on closures, reflection, garbage collection, interface > proxies, stack dumps, debug info, and a bunch of other stuff. (There's a > Google code project for it, but I'm not encouraging people to go there > until I have more of the language finished.)I think it's great to write compilers to learn how languages work (I'm doing my own too). My points about the language: First, It's much more like a cross between Python/Perl and Java than C++. It's not strongly typed and yet it use generic programming. As long as it's not creating *types* with templates (like C++) but creating only generic algorithms (like Java), it's ok. It has too much syntactic sugar and names changed for no apparent reason, it drives the user away from using your language. A good deal of Java's success is because they used a syntax very similar to C++. My (very personal) point of view is that, if you're not bringing anything new, help the others that are instead of re-inventing the wheel. But again, if your point is (as mine) to learn, well done! It's much better than my own language! ;) cheers, --renato Reclaim your digital rights, eliminate DRM, learn more at http://www.defectivebydesign.org/what_is_drm
If your goal is to create a usable language, your best bet is to use it. Create a significant project and code it in your language. This will show you what the language/standard library still need, what coding tasks are too awkward to carry out, what practical advantages your language offers over alternatives, and so forth. A compiler for your language is an obvious first project to try out. This will exercise your language/standard library in parsing, interacting with external libraries (including but not limited to LLVM), file handling, data structure manipulation, and much more. Replace your original compiler piece by piece, and see how easy your language is to work with. Pay attention to the tasks that are painful or repetitive, and evolve you language to make those tasks easier.
Renato Golin wrote:> 2009/9/15 Talin <talin at acm.org>: > >> For example, here's what the "Iterator" interface looks like: >> >> interface Iterator[%T] { >> def next -> T or void; >> } >> > > So this would be something like: > > template <class T> > virtual class Iterator { > T next(); // or void? > }; > > So the power of having two types of return parameters is that you save > function calls (hasNext())? >There are other benefits as well. Having disjoint types makes library APIs cleaner - often a function will need to return either a result, or an error code. In C++, this has to be handled either via a reference parameter (which is inefficient because the compiler's live variable analysis can't determine if the value was assigned or not) or by returning a struct.>> def sum(nums:int...) -> int { >> var sum = 0; >> for i in nums { >> sum += i; >> } >> return sum; >> } >> > > I see you don't have types for variables, only for containers, > templates and functions. And yet you say your language is > statically-typed. If you do: >The type of a variable is optional - if omitted, it is deduced from the initializer.> var foo = 10; // I'd presume it's an int > foo /= 3; > > Would foo become a float? > > foo /= 1e200; > > Would it become a double? > > What happens if you pass foo as an int, and inside the function it > becomes a double (without your consent, by a combination of > parameters) and you try to return it as an int? > > > >> 'classify' is like a switch statement, except that the cases are types >> rather than values. It works with both disjoint types and polymorphic >> types, similar to what is seen in Scala and various functional languages >> such as OCaml. The variables in the individual 'as' clauses are never in >> scope unless the assignment to that variable actually succeeds, so >> there's no chance of seeing an uninitialized variable. >> > > Is it run-time or compile-time? The former is Java's insanceof/C++ > RTTI, the later has not many uses... > >It's like Java's "instanceof", i.e. a runtime type test.>> In any case, I don't want to go on about this too long - at least not >> until the compiler is in better shape to be shown to the world. I still >> need to work on closures, reflection, garbage collection, interface >> proxies, stack dumps, debug info, and a bunch of other stuff. (There's a >> Google code project for it, but I'm not encouraging people to go there >> until I have more of the language finished.) >> > > I think it's great to write compilers to learn how languages work (I'm > doing my own too). > > My points about the language: > > First, It's much more like a cross between Python/Perl and Java than > C++. It's not strongly typed and yet it use generic programming. As > long as it's not creating *types* with templates (like C++) but > creating only generic algorithms (like Java), it's ok. >It's not meant to "look" like C++ - it's meant to occupy the same ecological niche. I have many years of experience programming in Java, C# and Python, and I'm happy using those languages to write things like web servers and desktop applications. But there are some tasks which I *wouldn't* use those languages for - XBox games, MPEG decoders, AudioUnits, signal processing, and so on. For those kinds of tasks, I would normally use C++ - but over the years I have collected hundreds of gripes with C++, which I'd like to fix.> It has too much syntactic sugar and names changed for no apparent > reason, it drives the user away from using your language. A good deal > of Java's success is because they used a syntax very similar to C++. > > My (very personal) point of view is that, if you're not bringing > anything new, help the others that are instead of re-inventing the > wheel. But again, if your point is (as mine) to learn, well done! It's > much better than my own language! ;) > >I've only shown a small part of what I have. This forum is not the place for language advocacy, I don't want to start a discussion on the merits of my language or any other. I'm absolutely convinced that I have something to contribute, and I'm going to forge ahead despite the naysayers :) Mainly, I just wanted to share with the LLVM community how I am using LLVM, and I don't want the topic to stray too far from that.> cheers, > --renato > > Reclaim your digital rights, eliminate DRM, learn more at > http://www.defectivebydesign.org/what_is_drm > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >