Skip to content

Instantly share code, notes, and snippets.

@gosukiwi
Last active March 30, 2016 07:57
Show Gist options
  • Save gosukiwi/1cef1f934b1286e76c07 to your computer and use it in GitHub Desktop.
Save gosukiwi/1cef1f934b1286e76c07 to your computer and use it in GitHub Desktop.
alpha_sapphire draft

alpha_sapphire

Simplistic, interpreted, dynamic, object-oriented language inspired by Ruby and Coffeescript.

Simplistic

While trying to be expressive, the main focus on alpha_sapphire's syntax is to keep it simple. There is always a trade-off between expresiveness and complexity. For instance:

foo() unless bar == 2

Is more expressive than:

if bar != 2
    foo()
end

The downside is that it adds a bit of complexity. Because alpha_sapphire tries to be as small as possible, the first priority is simplicity.

Functional

Functions -- or code blocks, are first-class citizens, so you can use them when needed as you wish, a-la Ruby. A simple function looks like this

foo = fn ->
    return "Hello, World!"
end

If the function contains only one expression, it can be expressed as such:

foo = fn -> return "Hello, World!"

Also, the return is optional, the last evaluated expression is always returned.

foo = fn -> "Hello, World!"

You can receive functions as arguments and return them just like any other value.

addOne = fn x -> x + 1
result = [1, 2, 3].map(addOne) # result is now [2, 3, 4]
result = [1, 2, 3].map(fn x -> x + 1) # this also works

# this function returns another function which adds `n`
# to it's argument
addN = fn n ->
    fn x -> x + n
end
# addOne could be implemented as such
addOne = addN(1)

You can call functions just like any other language, by using ().

foo()

If the function requires no arguments, the parenthesis are not needed.

foo # call function foo

Arguments can be comma separated if you prefer, but only spaces are required

foo(1, 2, 3)
foo(1 2 3) # same

Object Oriented

Object oriented programming in alpha_sapphire aims to be as simple as possible. Thus, there is no inheritance or private methods, only mixins.

class Foo
    greet -> 
        "Hello, World!"
    end
end

class Bar
    include [:Foo]
end

Bar.new.greet

As with functions, if the method is a single expression, it does not need an end.

class Foo
    greet -> "Hello, World!"
end

Attributes are defined using @. In order to use them outside the class you need to implement getters and setters.

class Person
    init name, age ->
        @name = name
        @age = 22
    end
    
    name -> @name
    name= name -> @name = name
    
    age -> @age
end

p = Person.new("Mike", 28)
p.name # Mike
p.name = "John"
p.name # John

You are encouraged to use the helper methods get, set and get_set

class Person
    get_set [:name] # generate `name` and `name=` methods
    get     [:age]  # only generate `age` method
    
    init name ->
        @name = name
    end
end

Static methods and attributes are shared across all instances

class Foo
    shared do
        get_set [:age]
        
        init ->
            $age = 22
        end
        
        some_method ->
            "I am #{$bar} years old"
        end
    end
end

Foo.bar # 22
Foo.some_method

You can access shared stuff in instances too

class Foo
    some_instance_method ->
        $bar # 2
    end
    
    shared
        $bar = 2
    end
end

Syntax at a glance

a = 2
name = "mike"
let pi = 3.14 # cannot be changed

some_fun = fn ->
  2 # implicit return
end

some_fun # call, parens when no args are optional

class MyClass
  person = Person.new
  
  greet = fn name ->
    "Hi #{name}!"
  end
  
  # method call
  delegate :name, :person
end

# "static" methods and attributes
class Foo
  shared # this is not a method definition, it's a keyword/special construct
    name = "Mike"
    hi = fn -> "HI #{mike}" # if the function it's a single expression, no need for an end
  end
end
Foo.hi

# Mixins, object composition, method delegation, etc
# If it can't find a method on Foo, it will search in Bar, then in Baz.
# So if there is a repeated method, it uses the one which was included first
class Foo
  include [Bar, Baz]
end

# Namespaces, just split them
class Foo::Bar
end
Foo::Bar.new

# Arrays
arr = [1, 2, 3]
arr.each(fn -> print it) # when no parameter is specified, default to "it" to first
                         # parameter received, also, because it's a single statement
                         # function, no need for an end.
                         
# Hashes
h = { 'key': 1, foo: 'test str', 22: 'example' }

# Conditionals
if true # or unless false
  something
else
  something_else
end

# Or maybe
true.ifTrue(->
    something
end).ifFalse(->
    something_else
end)

# Iteration, should be avoided, use each instead
# or 10.times(fn -> print (it + 1))
while true
  break
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment