see also: http://www.slideshare.net/devstonez/introducing-the-ceylon-project-gavin-king-presentation-at-qcon-beijing-2011 string concatenation -------------------- goals: string concatenation is very common, so it should be easy but maybe it should be avoided in some cases? strings in general? make the performance clear to the programmer syntaxes: "hello " + name used by many languages, some people consider this to be a problem because the + operator gets two meanings. "hello " $ name a special string concatenation operator. Some languages use this, like PHP. "hello " name no operator at all, used by the POSIX shell script language. also, constants are concatenated this way in C. merge("hello ", name, NULL); could be done, but looks quite ugly String s = String.new("Hello"); s.append(name); parameters, structs and separators ---------------------------------- Pascal uses ";" as the only separator. This maks everything consistent, here's how it could look like in this new language: typedef Time = (int time; int minute); int time_diff(Time a; Time b); Time a, b; Additionally, this allows "," to be used when the same type is repeated, even in parameter lists: typedef Time = (int time, minute); int time_def(Time a, b); Time a, b; const by default? ----------------- var int sessionId = 0; typedef Time = ( int hour, minute; // struct members are not const by default ); var Time start; () add_time(var Time* time, int minutes); generics -------- The common syntax: List dates; But I think that parsing this could get complicated: A < B; Especially if repeated comparison operators are allowed: A < B > C; This is a problem because at the time of parsing, it might not be known whether A,B,C are types or objects. There are two more syntaxes that look good (IMO) and could work: List[Date] dates; List(Date) dates; With [] we have to distinguish it from array definitions, and with () we have to distinguish it from functions and parameter lists / structs. For example: int[10] constants; int[size] prices; List[Date] dates; That looks quite hard imo, especially int[size] vs List[Date]. Paranthesises might be a better choice: int[10] constants; int[size] prices; List(Date) dates; replace(constants, 3, 8) || sort(prices); List(Date).sort(); // List(Date) could be a function or a namespace! // On the other hand, this doesn't matter, because // both can evaluate to a namespace. generics and variable elements ------------------------------ List[int] a; // an immutable list of immutable elements List[var int] a; // an immutable list of variable elements var List[int] a; // a variable list of immutable elements var List[var int] a; // a variable list of variable elements typedef List[T] = lists ----- list initialization: int[] list = [1, 2, 3, 4]; list comprehensions: count size = 10; int[size] list = [i^2 for i in 0..size]; automatic list sizes count size = 10; int[] list = [i^2 for i in 0..size]; // compiler knows the length of list here list[9] = 0; type extension vs aliasing -------------------------------- typedef A is int typedef B extends A But this might be unnecessary, because type extension can be done through the "base" identifier in structs! repetitions ----------- use cases: typedef E = enum { a = 1; b = 2; c = 4; d = 8; } type enums & type-array dispatch -------------------------------- we want to simplify things like this: typedef EventType extends enum( Click; MouseDown; MouseUp; MouseOver; ); typedef Event = struct( EventType type; ); typedef ClickEvent = struct( Event base = (Click); int x, y; int buttons; ); ... () handle_event(Event e) { switch (e.type) { case Click: ClickEvent ce = ???; handle_click(ce); break; ... } } alternative, with "namespace substitution": namespace eventparams = { typedef Click = struct( int x, y; int buttons; ); }; typedef EventType extends enum(import eventparams); typedef Event extends struct( EventType type; union[type](import eventparams); ); () handle_event(Event e) { switch (e.type) { // shouldn't each entry in the handlers namespace implement some interface? case namespace(handlers) h: handlers.h(e.h); break; } } "namespace substitution" could also work with loops and arrays: for (namespace h : handlers) { } ()()*[] triggerfuncs = [import triggers]; triggerfunctions[3](); shorthand for "this" code pattern (OO paradigm) ----------------------------------------------- Use $ as a shortcut, like Zimbu does: http://www.zimbu.org/design/classes-and-modules For instance: typedef A = ( int x, ); int A:$work(int y) // how can we say that "this" should be mutable? { $x += y; } becomes: typedef A = ( int x, ); int A:work(var A^ this, int y) { this^.x += y; } "empty" values and "or-empty"-operator (when) --------------------------------------------- namespace string { typedef here = ....; string empty_value = ""; // could be an "is_empty(x)" function also } () fizzbuzz() { for i in range(100) { // empty value for string is "" string line = ("fizz" when i mod 3 == 0) + ("buzz" when i mod 5 == 0) + "\n" line.print(); } } thing^? get_thing() { other^? o = get_other(); // empty value for thing^? is none return o?^.extract_thing() when o != none; } first-non-empty operator ------------------------ a = "" b = "x" c = "y" v = a else b else c // "x" free-after-use operator ----------------------- Free's the object as soon as it has been used. Thing own^ getThing(); printThing(getThing()~); // free'd after printThing returns printName(getThing()~^.getName()~); // value from getThing is free'd after getName returns. Value from getName is free'd after printName returns. Thing own^ a = getThing(); printThing(a~); // free'd after printThing returns //a^.getName(); // NOT ALLOWED! require-block ------------- behaves like if, but with a different name for clarity. if action == "POST" { require name != none and thing != none { // ... } else { log.error("missin parameters"); } } choice statement ---------------- bool value = choice { if a == none choose false; if a == b choose true; choose false; }; This generates a temporary that's assigned by the statement, which is then assigned to the "value" variable. This can also be used as an alternative to the "then-else" statement: int x = (a == b then 42 else 0); // equivalent int x = choice { if a == b choose 42; else choose 0; }; generalize the "alias" keyword ------------------------------ "alias" can be used for macros/inlining also! alias float PI = 3.1416; alias float tan(float x) return sin(x) / cos(x); with blocks and alternatives ---------------------------- With block: // syntax // resources need to be inited before their first "exit path". with type1 resource1 [= init1], type2, resource2 [=init2]... { ... } // example with FILE^ f = fopen("test.txt", "w") { fputs("hello", f); } Declaration qualifier (like "alias"): autofree FILE^ f = fopen("test.txt", "w"); fputs("hello", f); controlling endianess of constants ---------------------------------- // we can't use a-f and we shouldn't use number-like characters such as "l" or "O" // we also shouldn't use things that could be confused with C syntax, such as L, U, d etc. uint16 a = 0x1234'L; // little endian uint16 b = 0x1234'B;