├── README.md ├── Chapter04.md ├── Chapter03.md ├── Chapter02.md └── Chapter01.md /README.md: -------------------------------------------------------------------------------- 1 | # Programming InFancy # 2 | ## An OpenSource Book to teach the Fancy Programming Language. ## 3 | 4 | This is a work-in-progress book for learning the Fancy Programming 5 | Language. 6 | Each chapter is in its own .md file, starting with [Chapter01.md][] which 7 | gives a short introduction into Fancy's basic concepts and ideas. 8 | 9 | # [Start reading →][Chapter01.md] 10 | 11 | [Chapter01.md]: Chapter01.md 12 | -------------------------------------------------------------------------------- /Chapter04.md: -------------------------------------------------------------------------------- 1 | # Chapter 04 # 2 | 3 | ## 4.1 More Blocks ## 4 | 5 | Blocks play a vital role in Fancy. They're used for many different 6 | things that all have one thing in common: Allow seperation of concerns 7 | in a natural way and providing the possibility to write code close to 8 | your problem domain. This means writing DSLs in Fancy is a natural and 9 | easy thing to do, due to the keyword-based message syntax. 10 | 11 | ## 4.2 Partial Blocks ## 12 | 13 | Fancy has the concept of Partial Blocks. 14 | Partial Blocks behave like regular Blocks but have their argument 15 | ommitted. They always only take one argument which is implicit and 16 | that argument gets prefixed into any message send within the Block as 17 | its receiver. They allow Ruby-style simple DSLs while not relying on 18 | `instance_eval`, as many Ruby DSLs do, thus preserving things like the 19 | binding of self within the Block. Examples for libraries using 20 | `instance_eval` heavily are Sinatra and parts of Ruby on Rails. 21 | 22 | One good example is Fancy's built-in 23 | [HTML Generator Class](https://github.com/bakkdoor/fancy/blob/master/lib/html.fy) 24 | which can be used for writing Webapps, for example. I wrote a simple 25 | url-shortener webapp with Sinatra for Fancy. See 26 | [here](https://github.com/bakkdoor/shortefy). 27 | You'll also find a link to a Screencast there. 28 | 29 | Let's have a look at what I mean. 30 | 31 | ### 4.2.1 Without Partial Blocks ### 32 | 33 | ```fancy 34 | require: "html" 35 | 36 | html = HTML new: |h| { 37 | h html: |h| { 38 | h head: |h| { 39 | h title: "Using HTML Class" 40 | } 41 | h body: |h| { 42 | h div: { id: "header" } with: |h| { 43 | h h1: { class: "title" } with: "My Title" 44 | } 45 | h div: { id: "footer" } with: |h| { 46 | h h3: "The End." 47 | } 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | ### 4.2.2 And the same code with Partial Blocks ### 54 | 55 | ```fancy 56 | require: "html" 57 | 58 | html2 = HTML new: @{ 59 | html: @{ 60 | head: @{ 61 | title: "Using HTML Class" 62 | } 63 | body: @{ 64 | div: { id: "header" } with: @{ 65 | h1: { class: "title" } with: "My Title" 66 | } 67 | div: { id: "footer" } with: @{ 68 | h3: "The End." 69 | } 70 | } 71 | } 72 | } 73 | ``` 74 | 75 | Both code snippets will produce this output: 76 | 77 | ```html 78 | 79 | 80 | 81 | Using HTML Class 82 | 83 | 84 | 85 | 90 | 95 | 96 | 97 | ``` 98 | 99 | Since Partial Blocks preserve the meaning of self, you can use the 100 | HTML generator class for your view code and don't need to use a 101 | seperate template language, as all instance variables will be bound 102 | nicely, depending on where you put that code. -------------------------------------------------------------------------------- /Chapter03.md: -------------------------------------------------------------------------------- 1 | # Chapter 03 # 2 | 3 | ## 3.1 Numbers ## 4 | 5 | As any programming language, Fancy has number literal syntax built in. 6 | 7 | ### 3.1.1 Integers (Fixnums) ### 8 | 9 | There are multiple ways to write a `Fixnum` (Integer value). Here's a list of possible ways to write a `Fixnum`: 10 | 11 | * `1`, `123`, `1_000_000`, `999_888_777` etc. Underscores are ignored and used purely to be easier to read (especially large numbers) 12 | * Binary literals: `0b10101`, `0B01010101111` 13 | * Hexadecimal literals: `0xff`, `0xAB`, `0XAF` 14 | * Octal literals: `0o77`, `0O13` 15 | 16 | ### 3.1.2 Floats ### 17 | 18 | Floats only allow one way of writing them: `10.9997`, `0.123`, `1.0` 19 | 20 | **Note:** Both Fixnums and Floats can be prefixed with a `-` for negative numbers. 21 | 22 | 23 | ## 3.2 Strings ## 24 | 25 | Strings are what you expect them to be. 26 | 27 | Examples: 28 | 29 | ```fancy 30 | "Hello, World" 31 | "Hello,\n World" 32 | 33 | """ 34 | This is a multi-line String 35 | The newlines become part of the String and start and end with a triple quote, 36 | just as in Python. They're most commonly used for docstrings, which we'll talk about 37 | later (also copied from Python). 38 | """ 39 | ``` 40 | 41 | Fancy also has support for Ruby-like string interpolation: 42 | 43 | ```fancy 44 | "This is a String with a value interpolated: 3 ** 3 = #{3 ** 3}" 45 | "Hello, #{name}, I'm #{age} years old." 46 | ``` 47 | 48 | ## 3.3 Symbols ## 49 | 50 | Symbols are unique identifiers. They're equivalent to Ruby's Symbols. 51 | 52 | Examples: 53 | 54 | ```fancy 55 | 'foo 56 | 'foo? 57 | 'foo:bar: 58 | 'foo_bar!?Baz!?! 59 | 'helloWorld 60 | 'hello123!?=* 61 | ``` 62 | 63 | 64 | ## 3.4 Tuples ## 65 | 66 | In contrast to Ruby and like Python, Fancy has built-in literal syntax for Tuples. Tuples are constant-sized containers with index-based access to members. 67 | 68 | Examples: 69 | 70 | ```fancy 71 | (1, 2) # Tuple with values 1 and 2 72 | (1, 2, "foo") 73 | ('foo, 'bar, "baz!") 74 | (1, (2, 3), (4, (5, 6, 7))) # nested Tuples 75 | 76 | # Accessing elements: 77 | (1, 2, 3) at: 2 # => 3 78 | (1, 2, 3)[0] # => 1 79 | ``` 80 | 81 | 82 | ## 3.5 Arrays ## 83 | 84 | One of the most used data structure are arrays. In Fancy there's the `Array` class which provides index-based constant time access to dynamically resizable (growing) polymorphic containers. 85 | Let's have a look at some `Array` examples: 86 | 87 | ```fancy 88 | # An Array containing 5 integers (Fixnums) 89 | [1,2,3,4,5] 90 | 91 | # An Array of 2 numbers, 1 String and another Array 92 | [1, 2, "An Array!", [4,5, "Yes, indeed!"]] 93 | ``` 94 | 95 | Arrays work the same way as they do, for example, in Ruby. In Fact, they're sharing the same Class as their Ruby equivalents. Anytime you're using a Fancy Array, you're also using a Ruby Array inside Rubinius. There is no wrapper in between. This is true not only for Arrays, but for all built-in types and classes where there is a Ruby equivalent available. 96 | 97 | 98 | ## 3.6 Hashes (Dictionaries, Hashmaps) ## 99 | 100 | Hashes are unordered collections of key-value pairs with fast access through keys. They can nest arbitrarily, just as Arrays. 101 | 102 | Examples: 103 | 104 | ```fancy 105 | <['name => "Fancy", 'type => "Programming Language", 'created => 2010]> 106 | ``` 107 | 108 | You can of course use any other type besides Symbols as keys and values. 109 | 110 | 111 | ## 3.7 Blocks (BlockEnvironment, Closures) ## 112 | 113 | One of the most heavily used literal values in Fancy are Blocks. They're used to implement nearly all control structures (like traditional `if`, `else`, `while` etc constructs) and are proper closures with interesting `return` semantics. 114 | 115 | We've seen Blocks in Chapter 1 before, but for completeness, here's a list of some literal Blocks: 116 | 117 | ```fancy 118 | { "A Block with no argument" println } 119 | |x| { "A Block with one argument, value: #{x}" println } 120 | |x y| { "A Block with two arguments, values: #{x} and #{y}" println } 121 | 122 | # Seperating arguments with comma is optional, thus this is valid as well: 123 | |x, y| { "The sum is: #{x + y}" println } 124 | ``` 125 | 126 | There's also *Partial Blocks* which can be used for Blocks only taking 127 | one argument: 128 | 129 | ```fancy 130 | @{ + 1 } # is the same as: |x| { x + 1 } 131 | # e.g.: 132 | [1,2,3,4] map: @{+ 1} # => [2,3,4,5] 133 | ``` 134 | 135 | To `call` a Block, you send it the `call` or `call:` message and pass the arguments in as an Array: 136 | 137 | ```fancy 138 | block = |x, y| { x + y println } 139 | block call: [2, 3] # will print 5 140 | ``` 141 | 142 | 143 | ## 3.8 Regular Expressions ## 144 | 145 | Fancy, as Ruby or Perl, has Regular Expressions built-in to the 146 | language. In fact, it uses the same implementation that Ruby uses on 147 | top of Rubinius, including the same literal syntax: 148 | 149 | ```fancy 150 | /^Hello, (.*)!$/ 151 | /^[A-Z][a-Z0-9_:]$/ 152 | ``` 153 | 154 | 155 | ## 3.9 Ranges ## 156 | 157 | Fancy also has Ranges, like Ruby: 158 | 159 | ```fancy 160 | (1..10) 161 | (a..b) 162 | (x .. x ** x) 163 | ``` 164 | 165 | #### [Chapter 4][Chapter 4] will deal with one of Fancy's central features, namely Blocks, some more. #### 166 | 167 | [Chapter 4]: Chapter04.md 168 | -------------------------------------------------------------------------------- /Chapter02.md: -------------------------------------------------------------------------------- 1 | # Chapter 02 # 2 | 3 | ## 2.1 Class Definitions ## 4 | 5 | Classes in Fancy are first-class values (they are instances of the 6 | `Class` class, just as in Ruby or Smalltalk). 7 | 8 | There's several ways to define Classes in Fancy, but the common one is 9 | to use the built-in syntax for it. Compared to Smalltalk, where class 10 | definitions are just message sends as well, Fancy also provides syntax 11 | for doing so, just as Ruby and most other object-oriented programming 12 | languages out there. 13 | 14 | ```fancy 15 | class Person { 16 | } 17 | ``` 18 | 19 | Defines an empty class called `Person` which implicitly inherits from 20 | `Object`, the root class of Fancy's class hierarchy. 21 | 22 | To define a class that inherits from another class we specify the 23 | super class after a colon, like so: 24 | 25 | ```fancy 26 | class ImaginaryPerson : Person { 27 | # Person is the super class of ImaginaryPerson 28 | # ... 29 | } 30 | ``` 31 | 32 | 33 | ## 2.2 Method definitions ## 34 | 35 | Let's define a `name` method for `Person` which returns a `String` 36 | representing the name of a `Person` (for now we'll just use the same 37 | name for all instances of `Person`): 38 | 39 | ```fancy 40 | class Person { 41 | def name { 42 | "John Doe" 43 | } 44 | } 45 | ``` 46 | 47 | If we create a new `Person` now and send it the `name` message, we'll 48 | get "John Doe" as a response: 49 | 50 | ```fancy 51 | p = Person new 52 | p name # => "John Doe" 53 | ``` 54 | 55 | 56 | ### 2.2.1 Constructor method ### 57 | 58 | Let's refactor this code a little and define a constructor that takes 59 | a name and returns that when sent the `name` message: 60 | 61 | ```fancy 62 | class Person { 63 | def initialize: name { 64 | @name = name 65 | } 66 | 67 | def name { 68 | @name 69 | } 70 | } 71 | ``` 72 | 73 | As you can see, constructor methods *start* with `initialize`. In our 74 | case the constructor method just takes one argument, a name, and 75 | stores it into the *instance variable* `@name`. Instance variables 76 | start with `@` and *class variables* start with `@@`, just as in Ruby. 77 | 78 | Now we can create persons and pass in their names: 79 | 80 | ```fancy 81 | john = Person new: "John Doe" 82 | betty = Person new: "Betty Boop" 83 | john name # => "John Doe" 84 | betty name # => "Betty Boop" 85 | ``` 86 | 87 | Constructor methods like `initialize:` are just normal instance 88 | methods, like `name`. They're called with the appropriate arguments 89 | when calling the `Class##new:` class method. For constructors with 90 | multiple arguments, the necessary class constructor methods are 91 | created for you implicitly. Let me show you what I mean: 92 | 93 | ```fancy 94 | class Person { 95 | def initialize: name age: age city: city { 96 | @name = name 97 | @age = age 98 | @city = city 99 | } 100 | 101 | def name { 102 | @name 103 | } 104 | 105 | def age { 106 | @age 107 | } 108 | 109 | def city { 110 | @city 111 | } 112 | } 113 | 114 | p = Person new: "John Doe" age: 42 city: "New York" 115 | p name # => "John Doe" 116 | p age # => 42 117 | p city # => "New York" 118 | ``` 119 | 120 | When defining a method starting with `initialize:` it will create a 121 | corresponding class method replacing `initialize:` with `new:` and 122 | keeping the rest of the name. E.g. for an instance method called 123 | `initialize:age:city:` a class method `new:age:city:` is defined which 124 | passes all the arguments on to the `initialize` method. 125 | 126 | ### 2.2.2 Slot readers & writers ### 127 | 128 | There's a simpler way to define so-called *getter-* and 129 | *setter-methods* in Fancy: 130 | 131 | ```fancy 132 | class Person { 133 | # define getter-methods: 134 | read_slots: ['name, 'age, 'city] 135 | 136 | # or if, you'd want them all to be writable: 137 | write_slots: ['name, 'age, 'city] 138 | 139 | # or define both getter & setter methods: 140 | read_write_slots: ['name, 'age, 'city] 141 | } 142 | ``` 143 | 144 | We usually refer to *instance variables* as ***slots*** within 145 | Fancy. It's just a different name, but they refer to the exact same 146 | thing. 147 | 148 | `read_slots:` defines reader methods for all the slotnames within a 149 | given Array. `write_slots:` defines setter methods for the slotnames 150 | in a given Array. `read_write_slots:` does both at once. These methods 151 | are completely defined in Fancy and can be found in the `Class` class 152 | definition in Fancy's standard library. 153 | 154 | ### 2.2.3 More syntactic sugar ### 155 | 156 | OK, let's have a look at some more nice syntactic features Fancy 157 | provides for common idioms in method definitions. 158 | First, let's have a look at all the code for the `Person` class we've 159 | written so far. We'll modify it a little to have multiple constructor 160 | methods to emulate default arguments for the missing arguments: 161 | 162 | ```fancy 163 | class Person { 164 | def initialize: name { 165 | initialize: name age: 42 # default is 42 166 | } 167 | 168 | def initialize: name age: age { 169 | initialize: name age: age city: "New York" # default is "New York" 170 | } 171 | 172 | def initialize: name age: age city: city { 173 | @name = name 174 | @age = age 175 | @city = city 176 | } 177 | 178 | # slot readers 179 | 180 | def name { 181 | @name 182 | } 183 | 184 | def age { 185 | @age 186 | } 187 | 188 | def city { 189 | @city 190 | } 191 | 192 | # let's also define slot writer methods: 193 | 194 | def name: new_name { 195 | @name = new_name 196 | } 197 | 198 | def age: new_age { 199 | @age = new_age 200 | } 201 | 202 | def city: new_city { 203 | @city = new_city 204 | } 205 | } 206 | ``` 207 | 208 | OK, and now let's define the same stuff with some standard helper 209 | methods and syntax sugar: 210 | 211 | ```fancy 212 | class Person { 213 | read_write_slots: ['name, 'age, 'city] 214 | 215 | def initialize: @name age: @age (42) city: @city ("New York") { 216 | } 217 | } 218 | ``` 219 | 220 | Yup, that's it. =) 221 | What's happening here is we're defining getter & setter methods for 222 | the slots `@name, @age` and `@city` and use Fancy's auto slot assignment 223 | syntax in the constructor method, which sets the slot with the given 224 | name to the value passed in as the argument. Finally, we're also using 225 | default argument values (any expression within `(` and `)`). Note, 226 | that you're allowed to refer to arguments passed in further left as 227 | default arguments further right. 228 | 229 | For example: 230 | 231 | ```fancy 232 | def hello: name1 and: name2 (name1) { 233 | "Hello, #{name1} and #{name2}!" println 234 | } 235 | 236 | # call with both arguments: 237 | hello: "Robert" and: "Meggie" # prints "Hello, Robert and Meggie!" 238 | 239 | # call with one argument: 240 | hello: "Max" # prints "Hello, Max and Max!" 241 | ``` 242 | 243 | 244 | #### The [next chapter][Chapter 3] will introduce some built-in classes with literal support commonly used in the language. #### 245 | 246 | [Chapter 3]: Chapter03.md 247 | -------------------------------------------------------------------------------- /Chapter01.md: -------------------------------------------------------------------------------- 1 | # Chapter 01 # 2 | ## 1.1 What is Fancy ? ## 3 | 4 | Fancy is a dynamic, concurrent, pure object-oriented general purpose 5 | programming language inspired by 6 | [Smalltalk](http://en.wikipedia.org/wiki/Smalltalk), 7 | [Ruby](http://en.wikipedia.org/wiki/Ruby_programming_language), and 8 | [Erlang](http://en.wikipedia.org/wiki/Erlang_programming_language). 9 | It runs on [Rubinius](http://www.rubini.us). 10 | 11 | The goal is to create a language implementation that is easy to 12 | understand and improve, even for people new to implementing 13 | programming languages. 14 | 15 | Fancy is a self-hosted language. That means, its compiler is written 16 | in Fancy itself. Apart from the compiler, Fancy's standard library is 17 | mostly written in Fancy, too. The standard library is a good starting 18 | point if you want to get a better feel for the language and its 19 | built-in classes and methods, once you've mastered the fundamental 20 | semantics and syntax. 21 | You can view the standard library classes on GitHub 22 | [here](https://github.com/bakkdoor/fancy/blob/master/lib/). 23 | 24 | OK, enough said, let's get started with Fancy's basic concepts. 25 | 26 | 27 | ## 1.2 Basic concepts ## 28 | 29 | Fancy is heavily inspired by 30 | [Smalltalk](http://en.wikipedia.org/wiki/Smalltalk), a pure 31 | object-oriented, 32 | [message passing](http://en.wikipedia.org/wiki/Message_passing) 33 | dynamic programming language, developed at 34 | [XEROX PARC](http://www.parc.com/) in the 1970s and 1980s. 35 | 36 | The core idea of Smalltalk (and thus Fancy) is the concept of 37 | **message sending** (also called 38 | [*message passing*](http://en.wikipedia.org/wiki/Message_passing)). Fancy 39 | code interacts by sending messages to objects and getting responses 40 | while doing so. You can think of methods as message handlers for 41 | incoming messages on objects. In Fancy, as in Smalltalk and Ruby, 42 | every value is an Object. There is no distinction between so-called 43 | *value types* (or *primitive types*) and *reference types*. 44 | 45 | 46 | ### 1.2.1 Message Sends ### 47 | 48 | In Fancy nearly all operations are done via *message sends*. While 49 | Fancy does have syntax for class & method definitions, importing files 50 | and so on, most of them are just syntactic sugar for equivalent message 51 | sends to objects. 52 | 53 | Let's have a look at how this looks syntactically. 54 | 55 | **No arguments:** 56 | 57 | ```fancy 58 | object message_name 59 | ``` 60 | 61 | **Single argument:** 62 | 63 | ```fancy 64 | object message_name: arg 65 | ``` 66 | 67 | Is a message send to `object` with a message called `message_name:` 68 | and an argument `arg`. As in Smalltalk (or Objective-C, which is 69 | inspired by Smalltalk), messages are keyword-based and so are 70 | methods. So, if you have multiple arguments in a message send, each 71 | argument is preceeded by a keyword (usually describing the argument). 72 | 73 | **Multiple arguments:** 74 | 75 | ```fancy 76 | object foo: arg1 bar: arg2 baz: arg3 77 | ``` 78 | 79 | The above shows a message send with three arguments for the 80 | `foo:bar:baz:` message. If `object`, its class or any superclass 81 | defines a method with the same name, it will get executed with the 82 | given arguments. If not, it will look for a method called 83 | `unknown_message:with_params:` within `object`s inheritance chain (as with 84 | Ruby's `method_missing`). 85 | 86 | Lets look at a more real-world example: 87 | 88 | ```fancy 89 | [1,2,3] each: |x| { 90 | x println 91 | } 92 | ``` 93 | 94 | This piece of code shows a message send to a literal Array consisting 95 | of the three number values **1**, **2** and **3**. The `each:` method 96 | expects a **Block** object (or actually, something *callable* - it needs 97 | to implement the `call` and `call:` methods). It will `call:` the 98 | argument given to it with each element in the Array. 99 | 100 | The `|x| { x println }` thing is a Block literal. Blocks are just 101 | normal objects but with built-in syntax (like strings, numbers and 102 | many more). As in Ruby, anything between the pipes (`||`) are arguments 103 | to the block and the code between the curly braces is the body of the 104 | block. Blocks are used as *anonymous methods* (also called *lambda 105 | functions*) and *closures* within Fancy. They are first-class values 106 | in the language, like any other object, and can be passed around to 107 | any method. In Fancy all control structures are implemented with 108 | blocks. But we'll get to that in a minute. 109 | 110 | First off, let's fully explain that code above. As mentioned, the 111 | `each:` method takes something that implements `call:` and passes it 112 | each element in the array in turn. You can think of `each:` being used 113 | as an **iterator**. In terms of the language, `each:` is just a method 114 | like any other though. 115 | 116 | The `println` send to `x` causes it to be displayed on 117 | `*stdout*`. Here's the implementation of `println`: 118 | 119 | ```fancy 120 | def println { 121 | # *stdout* is a dynamic variable 122 | # we'll discuss these later in detail 123 | *stdout* println: to_s 124 | } 125 | ``` 126 | 127 | You can find the code in *lib/object.fy* within Fancy's root source 128 | directory or just 129 | [click here](https://github.com/bakkdoor/fancy/blob/master/lib/object.fy#L29) 130 | to view it on Github. 131 | 132 | 133 | ### 1.2.2 Control Structures ### 134 | 135 | As mentioned before, Fancy hardly has any built-in control structures 136 | in contrast to most other programming languages out there. It's 137 | directly inspired by Smalltalk here in that all the usually built-in 138 | control flow structures are implemented with *Blocks* and their 139 | ability to *access variables outside of their scope (and preserve 140 | them)*. 141 | 142 | Let's look at the most common control structures found in other 143 | programming languages. 144 | 145 | 146 | **If/Else:** 147 | 148 | ```fancy 149 | x < y if_true: { 150 | "x is smaller than y" println 151 | } else: { 152 | "x is NOT smaller than y" println 153 | } 154 | ``` 155 | 156 | The `else:` part can be ommited, as there's also a method `if_true:` 157 | defined apart from `if_true:else:`. You can also write it the 158 | following (although longer) way: 159 | 160 | ```fancy 161 | if: (x < y) then: { 162 | "x is smaller than y" println 163 | } else: { 164 | "x is NOT smaller than y" println 165 | } 166 | 167 | # there's also this additional way of doing something conditionally: 168 | 169 | { "x is smaller than y" println } if: (x < y) 170 | ``` 171 | 172 | 173 | **While:** 174 | 175 | ```fancy 176 | x = 0 177 | { x < 10 } while_true: { 178 | x println 179 | x = x + 1 180 | } 181 | 182 | # or: 183 | 184 | x = 0 185 | while: { x < 10 } do: { 186 | x println 187 | x = x + 1 188 | } 189 | ``` 190 | 191 | 192 | **Endless loop:** 193 | 194 | ```fancy 195 | loop: { 196 | # do something here and possibly return when done 197 | } 198 | ``` 199 | 200 | **For-loop:** 201 | 202 | ```fancy 203 | 10 times: |i| { 204 | i println # will print 0 - 9 205 | } 206 | 207 | # or: 208 | 209 | 0 upto: 9 do: |i| { 210 | i println # same here. 211 | } 212 | ``` 213 | 214 | 215 | #### In [Chapter 2][], we'll have a look how class & method definitions work in Fancy. #### 216 | 217 | [Chapter 2]: Chapter02.md 218 | --------------------------------------------------------------------------------