https://github.com/lbovet/blabla
A new Java-compatible programming language
https://github.com/lbovet/blabla
Last synced: about 2 months ago
JSON representation
A new Java-compatible programming language
- Host: GitHub
- URL: https://github.com/lbovet/blabla
- Owner: lbovet
- Created: 2011-04-20T11:57:15.000Z (about 14 years ago)
- Default Branch: master
- Last Pushed: 2011-04-21T10:03:55.000Z (about 14 years ago)
- Last Synced: 2025-01-17T08:12:07.011Z (3 months ago)
- Homepage:
- Size: 105 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.asciidoc
Awesome Lists containing this project
README
BLABLA
======= BLABLA =
A new Java-compatible programming language
Author: Laurent Bovet
License: Do whatever you want with this but mention the original authors.
Please participate. Write your comments as https://github.com/lbovet/blabla/issues[issue] of this project or fork it.
== Features
* Mostly backwards-compatible with Java. Valid Java code is valid Blabla code! At least for the subset of features we really use (e.g. drop things like finalizers, generic wildcards)
* Object oriented
* Strongly, statically typed
* Concise
* Implementable on JVM. Code can be translated to Java source code
* Allows functional programming constructs (lambda) without making the function a first-class citizen
== Driving forces
* As simple, concise and practical as script langugage (ref Python)
* For javaists. A progressive transition to modernity
== Key Concepts
* Type inference
* A tuple type that can pack/unpack variable lists
* Default method on classes
== Examples=== General and Syntax
short builtin namespaces, no semicolon mandatory----
sys.println("Hello, world")
----Parentheses for statements are not mandatory
----
if a==1 {
sys.println("hello")
}while a < 4 {
a--
}
----
No distinction object/primitive types. Builtin types and classes are lowercase.----
int a = 2
----
All variables are nullable----
int a = null
----Type inference initialization at declaration
----
a = "a string"
----String are comparable with "=="
----
a = "a"
b = a + "b"
b == "ab" // is true
----Instanciation: "new" keyword is not mandatory
----
a = MyClass()
----
Methods: "void" keyword is not mandatory----
class A {
myMethod(string s)
}
----
Constructors: parent constructors can be used without redefinition in sub-classes----
class A {
A(boolean b) {
...
}
class B extends A { .. }
b = B(true)
----=== Method Parameters
Default values for parameters
----
myMethod(string name, dept="main") { ... } // declaration. Note that inference works also here,
// type of dept is deduced
myMethod("myself") // call
----Named parameters
----
myMethod(string name, dept="main", country="CH", code=41) { ... } // declaration
myMethod(name:"myself", code:33, country:"FR") // call
----=== Collections and Tuples
Usual collections as builtin type with quick literal initialization
----
list a = [1, 2, 3]
map m = { "3": 1, "a": 3 }
----Array-like indexing of list and maps, "=" is defined as replacement operation
----
sys.println(a[3])
m["a"] = 5
----Tuple builtin type, a fixed-length list with typed elements
----
tuple t = (3, "a")int i = (int)t[0] // array-like subscripting returns object reference (must be casted)
int i = t.0 // dot for static subscripting (allows only a literal integer) returns a typed reference
----Named tuples, elements are named.
----
tuple t = (3, "a")int i = (int)t[0] // dynamic index subscripting still works
int i = (int)t.1 // static index subscripting still works
int i = t.a // dot for static subscriptingint i = t["a"] // Reflective subscripting
----=== Multiple Return Value & Tuple packing/unpacking
Methods can return multiple values----
string, int myMethod() { ... }
a, b = myMethod()
----In fact the multiple returned value is a tuple, above statement is similar to
----
tuple t = myMethod()
a, b = t // unpacking of a tuple in separate variables
----Thus, method can have named return values (requires parentheses)
----
string val, int error myMethod() { ... }
if( a = myMethod() ).error == 0 {
sys.println(a.value)
}
----Packing of parameters into a tuple is automatic (if no ambiguity)
----
myMethod(tuple t) { ... } // declarationmyMethod("a", 3) // call
----The reverse is true (if no ambiguity)
----
myMethod(string, int) { ... } // declaration
tuple t = "a", 2
myMethod(t)
----Anonymous variable to "swallow" tuple element when unpacking (like in Go).
-----
x, _ = target getPoint()
-----
=== GenericsInference is also used with generics
----
Collection cc = LinkedList() // the compiler knows that it has to instanciate a LinkedList
l = list() // defaults to a list of "object"
----Tuple packing/unpacking works also in generics, but you have to group the parameters in separate <...> blocks to allow multiple tuples and avoid ambiguous matching
----
class C {
T do()
}c = C()
// is actually the same as
c = C>()sys.println(c.do().i)
----=== Modifiers & Accessors
Visibility: things are public by default. private, protected, package: same behaviour as in Java.
Properties. They are public fields with optional accessors.
----
class A {
int a // public field with default accessors
int b -> { // getter accessor
return b*2
} <- {
return b / 2 // setter accessor, not that b is the incoming value and the returned value is the one actually set
}
int c <-{} // set accessor is empty, read-only property
int d ->{} // get accessor is empty, write-only property
abstract c ->{ return b*3 } // property not stored, using other field. Can also be defined in interfaces.}
// Note: In "java compatibility mode", the compiler routes a.a to a.getA() and a.setA() automatically.
----=== Default Method, Lambda and With
Objects can have a default method. This opens door to functional programming constructs.
----
// Example with genericity
interface CallBack {
R default(T param)
}
class CharSum implements CallBack{
default { // Note that the default method signature is infered from the interface
sum = 0
for c : param.chars {
sum += c.int
}
return sum
}
}// declaration
myMethod(CallBack callback) {
int value = callback("hello") // calls the default method of the callback object
}// call
myMethod(CharSum())
----Anonymous classes overriding the default method
----
// call myMethod with a callback created on the fly
myMethod( CallBack() { default { return param.chars[0] }} ) // Note that the generic parameters are infered by the method signature (when possible)
----Syntactic sugar to write the same as above when 1) Using the default constructor 2) redefining only the default method
----
// equivalents to above
myMethod( CallBack():{ return param.chars[0] } )
myMethod( CallBack:{ return param.chars[0] } )
----Closures are realized by generalizing the above concept with tuples and using a builtin interface named "lambda"
----
// builtin lambda interface (lowercase because builtin)
interface lambda { // Generic parameters must be grouped to allow tuple packing/unpacking see above
R default(T args)
}
// declaration
myMethod( lambda closure) {
f, b = closure(4, "hello") // call the closure
}
// usage with indexed tuple
myMethod( lambda:{ return args.0*0.5, args.1 == "hello" } )
// usage with map-like tuple
myMethod( lambda:{ return args.position*0.5, args.name == "hello" } )
----
Resource management is solved the same way with a builtin class named "with" and an interface named "closable"----
// builtin "with" class
abstract class with {
with(T t, safe=true) { // constructor, does the actual call
try {
default(t) // do the work
finally {
try {
t.close()
} catch(Exception e) {
if safe {
throw e // by default, throw exception when closing error
}
}
}
}
abstract default();
}// usage
connection = datasource.connection
with(connection):{
// work...
}
----
=== For LoopThe "for" statement works also on iterators, not only on collections.
----
Iterator it = ..
for i: it {
sys.println(i*3)
}
----List comprehension: builtin maplist class that extends a list applies the default method
to all elements of the input list, including those added after creation.----
numbers = [1, 2, 3 ]roots = maplist(numbers):{ return Math.srqt(i) } // roots is [ 1, 1.41.., 1.73...,]
roots.clear()
roots.add(4) // roots is then [ 2 ]
----For information, implementation of maplist could be:
----
class maplist extends list {
T default(F f) {
return t
}
maplist(list l) {
for i : l
super.add( default(i)
}add(T t) {
super.add(default(i))
}// ...
}
----
=== Exceptions, Import ExclusionExceptions inheriting from "Exception" are no more checked exceptions. Methods must however declare them in throws clause.
Hide default imports to allow copy paste of Java code containing blabla keywords
----
import .-* // This will disable the default language imports (builtin types, lambda, with, ...)
import .lambda // Selectively import a class from default language imports (You see that the namespace root of default language imports is "")
import .-lambda // Selectively hide a class from default language imports
import .* // Valid but not necessary, done by default
----=== Traits
Traits, à la Scala
----
trait Similarity {
abstract boolean isSimilar(T t)
boolean isNotSimilar(T t) {
return ! isSimilar(t)
}
}class Employee extends Person, Similarity {
string personalNo
boolean isSimilar(Employee employee) {
return employee.name = this.name && employee.personalNo == this.personalNo
}
}
----=== Concurrency & Parallel Programming
Builtin class: synchronized queue. Useful for parallel programming
----
q = sync() // unbounded
q = sync(5) // bounded
q = sync([1, 2, 3], 10) // bounded, initialized with a list (generic type infered from argument).q.add(4) // wait if bounded and full
q.get() // wait if emptyq.wait() // wait until it is empty
----By value copy with transitive "const" keyword. Allows for concurrent processing without shared state.
----
class MyImmutableObject {final int a
final string b
MyImmutableObject(in a, string b) {
this.a = a
this.b = b
}
}myMethod(const RootObject param) { ... } // declaration, enforce the parameter to be immutable, it will use a direct reference
if the object is really immutable (only final fields), clone it otherwise. This mechanism is
apply recursively for referenced objects before execution. Beware, it can copy a lot of stuff!
This is about the same idea as serialization but with cloning. We can also make the compiler
enforce the const chain with "final const" which makes thing behave a bit like C++ const!a = const myObject // It can also be used as operator
anotherMethod(const myParam)
----Builtin class: parallel. Binds sync and closure to parallelize code.
----
// Code as it were implemented using java platform concurency tools
abstract class parallel {
parallel() {
Thread(Runnable() { run() { default() } }
}
parallel(sync s) {
s.put(object())
Thread(Runnable() { run() { default(); s.get() } }
}
parallel(sync s, Executor executor) { // In the case we use
s.put(object())
executor.execute(Runnable() { run() { default(); s.get() } }
}
abstract default;
}// Usage
parallel:{
logger.write("long information to compute...") // Do not block current thread
}// Join after treatment of all objects
s = sync()
for i : objectsToTreat {
currentObject = const i // ensures no surprise with shared state
parallel(s):{
// ... treatment code applied on currentObject
}
}
s.wait()
----Concurrency: other example for concurrent processing. Treating requests parallelly
----
requestQueue = sync(0) // Queue receives the requests (another threads feeds it)
// It blocks immediately until get is called on its = sync(10) // max number of concurrent threads
while true {
request = const requestQueue.get()
parallel(s):{
// ... Treat request
}
}
----