On 09/15/2011 03:14 AM, bearophile wrote:
Docs of Tart, a future system language:
http://docs.tart.googlecode.com/hg/intro/index.html

It looks very similar to D, with few idioms turned into nice syntax. It's in 
early stage of development.

The following are quotations from the docs, I have selected some nice ideas.

---------------------------

http://docs.tart.googlecode.com/hg/intro/types.html

@Flags enum Traits {
   ABSTRACT,
   FINAL,
   STATIC,

   MASK = ABSTRACT | FINAL | STATIC,
}

var x = Traits.ABSTRACT | Traits.FINAL;

The presence of the @Flags annotation causes a number of things to happen:

         The default sequence of initialization values is 1, 2, 4, 8, and so 
on, rather than 0, 1, 2, 3, etc. In other words, any enumeration constant that 
does not have an explicit initialization expression will be assigned the next 
available bit number after the previous value.
         The compiler will auto-generate the bitwise operators | and&  for that 
type.
         The compiler will also auto-generate the contains() method, which 
allows the use of the in operator, enabling expressions such as if ABSTRACT in 
traits.
         In the current version of Tart, the toString() method is not defined 
on flag enums.

Note

Tart enumerations do not support Java’s ability to add arbitrary properties to 
enums.

---------------------------


Nice.




Property Declarations

The def keyword can also be used to define a property. Properties are like 
variables, except that they are implemented using functions. Whenever you 
attempt to read from the property, the property’s get function will be invoked, 
and when you attempt to modify the value, the set function will be called.:

def myProp:int {
   get { return p; }
   set (value) { p = value; }
}

myProp = 1;   // Calls "myProp.set(1)"


imho D's way is superior because it does not waste the set and get keywords.


---------------------------

http://docs.tart.googlecode.com/hg/intro/functions.html

Like Python, parameters can be referred to by name as well as position:

print("Hello, World!\n", padding="");

Any parameter can be referred to by its keyword name. The normal mapping of 
arguments to formal parameters is that positional arguments are assigned first, 
in order, and then any keyword arguments are assigned to any remaining unfilled 
parameters.

Sometimes it is useful to specify a parameter that is “keyword only” meaning 
that it can only be specified via keyword instead of positionally. A semicolon 
can be used to segregate regular positional parameters from keyword-only 
parameters:

def print (format:String; npos:int=0, sep=false);

print("Hello world!", npos=1); // OK
print("Hello world!", 1); // ERROR - too many positional arguments

In the above example, only the format argument will be filled in by positional 
argument - to have additional positional arguments in this case would be an 
error.


Nice.

---------------------------

http://docs.tart.googlecode.com/hg/intro/classes.html

A protocol represents a contract which a type may conform to. A class or struct 
is said to support the protocol if that class or struct defines all of the 
method signatures that are defined by the protocol. Template arguments can be 
constrained to only match types which support a specified protocol. Classes may 
declare explicitly that they support a protocol, or the support can be 
determined implicitly.

A protocol is a kind of abstract type that defines a contract which another 
type can support. An example would be a “HasToString” protocol:

protocol HasToString {
   def toString ->  String;
}

I like this a lot.


---------------------------

The extend keyword allows you to add additional methods to a user-defined type:

/* Add an additional method to the String class. */
extend String {
   static def toUpperCase() { /* ... */ }
}

Note however, that you can’t actually change the runtime representation of a 
type this way. The reason is simple: The extend declaration may not be visible 
everywhere in the program. If you extend class String, some modules may only 
see the original, unextended class, while other modules will see the extended 
version of the class. In order for all of the code to interoperate, the runtime 
implementation of the class must be the same, regardless of the extension.

This means that the extension can only add certain kinds of things to a type, 
namely:

     Static methods or properties.
     Final methods or properties.
     Inner types and type aliases.
     Protocol inheritance declarations.

Extensions follow the same scoping rules as other declarations, meaning that 
they are only in effect if the scope in which they are declared is active.


ok.

---------------------------

Sometimes you need to test the type of a variable, the isa keyword can be used 
for this. It works for both reference types and union types:

if a isa float {
   // ...
}
[snip.]

I like the typesafe approach to unions. Is 'a' typed as a float in the if body?


http://docs.tart.googlecode.com/hg/intro/collections.html

Generator expressions and comprehensions

Tart supports “generator expressions” similar to those found in Python. A 
generator expression produces an iterator, which can be passed directly to the 
from() method of a collection:

let s0 = ImmutableSet[int].from(x * x for x in 0 .. 10);

The initializer-list syntax is also supported, as is the map key/value operator:

let s0:ImmutableSet[int] = {x * x for x in 0 .. 10};
let m0:ImmutableMap[int, int] = {x ->  x * x for x in 0 .. 10};


Nice.

Sequence Unpacking

Tart supports a Python-like ability to unpack variables from a sequence:

let a, b = [1, 2];
let a:int, b:int = [1, 2];

The last variable in the unpacking assignment can be a variadic argument, 
meaning it scoops up all the remaining values:

let a:int, b:int... = [1, 2, 3, 4];

As with function arguments, the ‘...’ syntax changes the type of the argument 
into an array of the explicitly declared type. So the type of b is actually 
int[], and would in the above example be assigned the value [2, 3, 4].

Variable unpacking works with regular assignment as well, allowing for the 
Python ‘swap idiom’ to exchange the values of two variables:

a, b = b, a;

The sequence-unpacking syntax is what allows you to return multiple values from 
a function:

def returnStringAndInt() ->  (String, int) {
   return "Hello", 12;
}

let a:String, b:int = returnStringAndInt();


Nice.

---------------------------

http://docs.tart.googlecode.com/hg/intro/macros.html

Tart macros are functions which execute in the compiler rather than at runtime. 
They are introduced with the macro keyword:

macro MyMacro(t:Type) ->  Type {
   // ...
}

One thing that is interesting about macros is that the arguments are not 
evaluated before calling the macro. In other words, when you call a macro with 
an argument of “1 + 2”, it does not pass the value “3”, but rather the 
unevaluated expression “1 + 2” (technically what gets passed is an AST 
fragment.) These expressions will be substituted inline in the body of the 
macro. This means that you can control how many times (if at all) the 
expression and its associated side effects are evaluated.

There are a number of built-in functions that give you access to the attributes 
of the AST. For example, stringify() converts an AST node into its string 
representation. This is used by the assert macro, which is another part of the 
Tart core library:

macro assert[%T](expression:T) {
   if not expression {
     throw AssertionError(stringify(expression));
   }
}


That is not 'a function that executes in the compiler', that is an AST macro.

---------------------------

http://docs.tart.googlecode.com/hg/intro/templates.html

Template guard conditions

A guard condition is an additional restriction on the kind of value that can be 
bound to a template. For example, suppose we wanted a template parameter to only 
bind to subclasses of “Node”, so we define a restriction using the subclass test 
operator<::

class Visitor[%T require %T<: Node] { /* ... */ }


The “require” clause must come after all of the template arguments:

class Visitor[%A, %B require %A <: %B] { /* ... */ }


The spec is not clear on whether or not

class Foo[%A <: InputRange, %B <: OutputRange]

works. (class Foo[%A <: InputRange] does work.)


// while loop, showing a test expression that also declares a variable.
while let m = re.match(str) {
  console.stdout.writeLn(m.group(1));
}

*clap, clap, clap*


No ctfe. No string mixins. D wins. I think something like the protocol feature might be a worthy addition, considering the fact that implicit static interfaces are an integral part of D programming.





Reply via email to