Let's say you find a couple of pages with source code. How would you tell whether it is written in Freya or not? If it looks like a Pascaloid object oriented language, probabilities are hot... that what you have in your hands had been written in Freya, Chrome or even in Delphi.NET (if the author didn't use any hybrid features). This set of features may help you to find the answer.
This is, perhaps, the most striking feature you'll find when reading your first Freya example. Despite its Pascal roots, Freya has no units. As in C#, a Freya project is compiled by joining and parsing all files in the project. Each file contains several public and private sections, for declaring types, and separate implementation sections, one or more for each class or record.
using System, System.Collections.Generics; namespace Freya.DataStructures; public KdTree = class[X] ... end; QuadTree = class[X] ... end; implementation for KdTree[X] is ... implementation for QuadTree[X] is ... end.
One of the consequences of this design is how extremely easy you can separate the declaration from a class implementation. Consider what happens with Eiffel: you need a tool to extract the so-called "short form" for documentation. C# benefits from a highly sophisticated editor which implements code outlining. On the other hand, this separation is easier to achieve in languages from the Pascal family, but most of their encapsulation techniques were developed for the structured programming style. For instance, you're still forced in Delphi to write too many implementation details of your class in the interface section, inside a private scope. On the contrary, Freya allows those private features to be declared along with the class, or better, to be directly declared in the implementation section.
You need just one line to declare and implement a field-based property:
property Name: String;
If you don't provide an explicit implementation, the compiler will assume you want a field-based property, and it will declare a hidden field and the corresponding access methods. All references to this property inside its owner class, are translated as references to the hidden field.
Though C# 3.0 has added a similar feature, there's still a big advantage with Freya's: when the property is not declared neither abstract nor virtual, the implementation field is declared internal, and all classes in the same assembly may directly access the field instead of the property.
The syntax for defining an iterator in Freya is inspired by the CLU programming language. We think that our iterators, though functionally equivalent to C# v2.0 iterators, are easier to write, understand and maintain.
The Eiffel programming language, by Bertrand Meyer, has been an inspiration through many years for language designers. We have borrowed from Eiffel the very concept of Design by Contract (DbC, from now on), and most related features: preconditions, post-conditions and class invariants. However, there's no support right now in Freya for loop variants and invariants.
Please note that Chrome also supports Design by Contract, though there are differences in how both languages implement these features. Chrome, for instance, doesn't allow assertions in interface types, wasting a valuable resource. When you declare in Freya an assertion inside an interface type, all classes implementing the interface automatically copy the corresponding assertions.
We had to do some syntactic adjustments in order that properties could benefit from DbC. In theory, a property is just syntactic sugar for a couple of accesor/mutator methods... with some additional implicit assertions. A property, then, could feature up to four assertion blocks: two preconditions and two post conditions. We only had to add two new clauses to the assertions syntax: "for read" and "for write".
The original Eiffel specification had not separate interface types. C#, Java and Delphi are mainstream programming languages that use interface types, but up to this date, they doesn't support assertions (rumor has it that a future CLR version could offer explicit support for assertions). Freya has the best of both worlds, and methods declared as part of an interface type can have preconditions and post-conditions, and they are automatically propagated to any class implementing the type.
Freya also allows iterators to be declared as a regular feature in an interface type. Though C# v2.0 provides iterator blocks, you still have to use the explicit interfaces IEnumerator<X> and IEnumerable<X> in order to enforce the implementation of iterators in related classes.
Freya provides special attributes (such as commutative and associative) that can be used with an overloaded operator declaration. These attributes are detected and handled by the compiler. If you declare a binary operator* receiving a Vector and a System.Double, you can add a commutative attribute and avoid programming the symmetric operator that receives a System.Double and a Vector, in this order. Even when both operands belong to the same type, there's an advantage when using commutative and associative: this extra information could be used by the optimizer to reduce the complexity of expressions involving the operator.
There's another important advantage regarding these attributes, but it's often overlooked: they provide information about the contract implemented by the operator. Though the current implementation doesn't allow testing the veracity of these assertions, it's by any means a very useful hint about the operator's behavior.
Compound assignments in the C/C++/C# style may add a performance advantage in some situations, and, when are used carefully, they may even enhance source code legibility. The trick is to avoid compound assignments acting as expressions. Something similar happens with C's increment and decrement: they can be a blessing if you restrain yourself not to use them as expressions. And that's what Freya does: you can use compound assignments in statements, but not as part of expressions, and there are increment and decrement statements, using the postfix variant of C's operators.
The original Pascal specification only included a handful of operators: the traditional four arithmetic operators, comparisons, three Boolean operator... and two special operators for integer division and remainder. Boolean and integer operators were represented with reserved words, for the sake of clarity. When Borland extended Pascal to support new operators, most of them were implemented via reserved words. This was possible thanks to the absence of any compound assignments. Since Freya supports compound assignments, it's logical to expect you could use C style operators. Actually, Freya allows you to write operators following both styles. For instance, you could execute an exclusive "or" operation both with the "^" symbol, as in C/C++/C#, or with Delphi's "xor" reserved word. Also, Freya supports string constants delimited both by double and single quotes.
Pascal was designed, back in the seventies, with simplicity as its main goal. Niklaus Wirth felt that too many precedence levels for operators would complicate learning the language. In practice, however, Pascal syntax would have benefited from at least two more level of precedence. That way, you could write logical expressions containing Boolean operators without resorting to parentheses.
Freya adds those two desirable levels, as in SQL expressions, and even another level for two new logical operators. These operators implement the logical consequence and equivalence, and they are useful for writing complex assertions. There's another apparent concession to those familiar with the syntax of SQL expressions: you can use the "not in" and "is not" idioms for negating the result of "in" and "is" operators.
While C# allows only one set of possibly overloaded indexers, Freya supports the most general model implemented at the CLR level, and allows named indexers.
Object initializers have been introduced by C# 3.0, to simplify instantiation and further initialization:
var DS := new DataSet('MyDataSet', CaseSensitive := true);
Object initializers in Freya are merged with constructor calls, and they look like named parameters from other programming languages.
If the class being instantiated implements the ICollection[T] generic interface type, you can append a collection initializer after the parameter list:.
var L := new List[Integer]![1, 4, 9, 16];
In the previous example, the constructor has no parameters, but you can mix parameters, collection initializers and even object initializers in a same constructor call.
This is an area where design is still going on, but we can already advance some results. From its very conception, Pascal supported sets of certain base types. Unfortunately, this is not a very orthogonal feature, since you can't declare sets of real values, classes, etc. Freya breaks the link between the Set data type and its physical representation. Now, more data types may benefit from set constructions, as the in operator and the special syntax for creating set constants. Freya determines whether a data type supports these operations the same way C# and Freya detects whether a data type supports the foreach operator: looking for some implemented interfaces.
This summary does not pretend to be exhaustive in any way. You can find more oficial information about Freya in the Freya manifest (PDF).