module Stringfrom Microsoft.FSharp.Core
Multiple itemstype Format<'Printer,'State,'Residue,'Result> = PrintfFormat<'Printer,'State,'Residue,'Result>Full name: Microsoft.FSharp.Core.Format<_,_,_,_>--------------------type Format<'Printer,'State,'Residue,'Result,'Tuple> = PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple>Full name: Microsoft.FSharp.Core.Format<_,_,_,_,_>
val sprintf : format:Printf.StringFormat<'T> -> 'TFull name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val ( Util.reverse works ) : unit -> 'aFull name: index.( Util.reverse works )
val res : obj
namespace Microsoft.FSharp.Core
val printfn : format:Printf.TextWriterFormat<'T> -> 'TFull name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val x : objFull name: index.x
val y : objFull name: index.y
val data : objFull name: index.data
union case Option.None: Option<'T>
val add : x:int -> y:string -> floatFull name: index.add
val x : int
Multiple itemsval int : value:'T -> int (requires member op_Explicit)Full name: Microsoft.FSharp.Core.Operators.int--------------------type int = int32Full name: Microsoft.FSharp.Core.int--------------------type int<'Measure> = intFull name: Microsoft.FSharp.Core.int<_>
val y : string
Multiple itemsval string : value:'T -> stringFull name: Microsoft.FSharp.Core.Operators.string--------------------type string = System.StringFull name: Microsoft.FSharp.Core.string
Multiple itemsval float : value:'T -> float (requires member op_Explicit)Full name: Microsoft.FSharp.Core.Operators.float--------------------type float = System.DoubleFull name: Microsoft.FSharp.Core.float--------------------type float<'Measure> = floatFull name: Microsoft.FSharp.Core.float<_>
val failwith : message:string -> 'TFull name: Microsoft.FSharp.Core.Operators.failwith
Multiple itemstype Test = new : unit -> Test member Invoke : args:int [] -> obj member Item : float member Item : float with setFull name: index.Test--------------------new : unit -> Test
member Test.Invoke : args:int [] -> objFull name: index.Test.Invoke
val args : int []
type obj = System.ObjectFull name: Microsoft.FSharp.Core.obj
val __ : Test
member Test.Item : float with setFull name: index.Test.Item
val set : elements:seq<'T> -> Set<'T> (requires comparison)Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.set
val v : float
type unit = UnitFull name: Microsoft.FSharp.Core.unit
module string_decoderfrom index
type NodeStringDecoder = interface abstract member detectIncompleteChar : buffer:'a0 -> float abstract member write : buffer:'a0 -> 'a1 endFull name: index.string_decoder.NodeStringDecoder
abstract member NodeStringDecoder.write : buffer:'a0 -> 'a1Full name: index.string_decoder.NodeStringDecoder.write
abstract member NodeStringDecoder.detectIncompleteChar : buffer:'a0 -> floatFull name: index.string_decoder.NodeStringDecoder.detectIncompleteChar
val StringDecoder : NodeStringDecoderFull name: index.string_decoder.StringDecoder
Fable: the what, the why and the how
Bringing together the F# and JS worlds
meets
WHO IS MAKING THIS PRESENTATION?
Alfonso Garcia-Caro
- Degree in Linguistics
- Lived in Japan, Germany (back in Spain now)
- 5 years .NET experience
- 2 years F# and JS experience
-
Developed desktop, mobile and web apps for videogame,
green energy and education industries
Working at toggl.com, the insanely simple time tracking app
Give it a try!
WHAT IS FABLE?
- F# to JS compiler
- Source maps
- Plugin system
- Framework agnostic
- Batteries charged: F# core library and some .NET BCL
NOT AND AD-HOC LANGUAGE
- F# is a general purpose language mainly targeting .NET
- Not crafted specifically to compile to JS, like Dart, TypeScript or Elm
- Allows you to reuse your knowledge: semantics, tooling and APIs
BUT BEHAVES LIKE ONE
- No runtime
- Compiles to clean JS code
- Great interoperability with JS libraries
- Adheres to standard practices and workflows
- Compatible with JS developments tools: Babel, npm, WebPack
WHY FABLE?
JavaScript is evolving at rapid pace, do we need a new language?
ES2015 adds many great features and JS development tools keep getting better and better
But there are still things some programmers miss:
- Static typing
- Great editor support out of the box
- Comprehensive core library
F# brings this and a couple more features...
- REPL
- Intellisense
- Type inference
- Custom operators
- Whitespace indentation (optional)
- Expression based programming
- Pattern Matching
- Active Patterns
- Immutable by default
- Partial application / Pipelines
- Functional core library (LINQ on steroids!)
- Observables
- String formatting
- Structural comparison
- List, array and iterable comprehensions
- Generics, unions, records and tuples
- Type aliases
- DSL embedded in the language
- Typed-stateless Async programming
- OOP: Inheritance, interfaces, abstract classes
- Custom computation expressions
- Overloading, type extensions
- Type providers (coming to Fable)
- Units of measure
- Circular dependency restriction
- Compiler directives
- An excuse for being condescendant with non-functional programming
- Don Syme retweeting you!
And the killer feature...
LEFT PADDING OUT OF THE BOX!
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
// Explicit
"3.14".PadLeft(10) // " 3.14"
"3.14".PadRight(10) // "3.14 "
"22".PadLeft(10, '0') // "0000000022"
// With .NET string formatting
String.Format("{0,10:F1}", 3.14) // " 3.1"
String.Format("{0,-10:F1}", 3.14) // "3.1 "
// With F# typed string formatting
sprintf "%10.1f" 3.14 // " 3.1"
sprintf "%-10.1f" 3.14 // "3.1 "
sprintf "%+010i" 22 // "+000000022"
HOW DOES FABLE WORK?
This is what a day in the life of a compiler looks like:
Parse and validate text into an Abstract Syntax Tree
Make necessary transformations on that AST
Generate new code from the AST: assembly, bytecode, JS...
As Fable works with known languages it can take advantage
of existing tools.
F# compiler, like Roslyn, can be used as a service:
we completed the first step for free!
Unfortunately JS is not a compiled language
...or is it?
Babel generates an AST from ES2015 code,
applies transformations with a pluggable system
and generates ES5 JavaScript code.
Fable builds a bridge between F# and Babel AST
delegating the reponsibility of code parsing and generation.
Fable adds its own AST for internal operations:
HOW CAN I USE FABLE?
Fable can be downloaded from npm
1:
2:
3:
4:
5:
6:
7:
8:
mkdir temp
cd temp
npm init --yes
npm install -g fable-compiler
npm install --save fable-core
echo "printfn \"Hello World\"" > hello.fsx
fable hello.fsx
node hello.js
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
{
"module": "commonjs",
"outDir": "out",
"sourceMaps": true,
"projFile": "src/Fable.Samples.React.fsproj",
"babelPlugins": ["transform-runtime"],
"scripts": {
"prebuild": "npm install",
"postbuild": "node node_modules/webpack/bin/webpack"
},
"targets": {
"debug": {
"watch": true,
"symbols": ["DEBUG"],
"scripts": {
"postbuild": "node out/server"
}
}
}
}
TESTING
NUnit or Visual Studio tests can be compiled to JS too
1:
2:
3:
4:
5:
6:
7:
8:
9:
#r "../../../packages/NUnit/lib/nunit.framework.dll"
#load "util/util.fs"
open NUnit.Framework
[<Test>]
let ``Util.reverse works``() =
let res = Util.reverse "yllihP"
Assert.AreEqual("Philly", res)
Compile the tests using NUnit plugin and run them with Mocha
1:
2:
3:
4:
5:
fable samples/node/console/tests.fsx -m commonjs
--outDir out --plugins build/plugins/Fable.Plugins.NUnit.dll
node build/tests/node_modules/mocha/bin/mocha
samples/node/console/out/tests.js
INTERACTING WITH JS
We don't want to just intrude the JS ecosytem,
we want to take advantage of its full potential.
Because .NET community is great
F# community is fantastic
JS community is...
HUGE
...and amazing too :)
DYNAMIC PROGRAMMING WITH FABLE
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
open Fable.Core
printfn "Value: %O" jsObj?myProp // Property access
jsObj?myProp <- 5 // Assignment
let x = jsObj?myMethod $ (1, 2) // Application
let y = createNew jsCons (1, 2) // Apply `new` keyword
let data = // JS literal object
createObj [
"todos" ==> Storage.fetch()
"newTodo" ==> ""
"editedTodo" ==> None
"visibility" ==> "all"
]
JS MACROS
Use Emit attribute to emit JS code directly
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
open Fable.Core
[<Emit("$0 + $1")>]
let add (x: int) (y: string): float = failwith "JS only"
type Test() =
// Rest arguments
[<Emit("$0($1...)")>]
member __.Invoke([<ParamArray>] args: int[]): obj =
failwith "JS only"
// Syntax conditioned to optional parameter
[<Emit("$0[$1]{{=$2}}")>]
member __.Item
with get(): float = failwith "JS only"
and set(v: float): unit = failwith "JS only"
FOREIGN INTERFACES
Define foreign interfaces easily to get the benefits of static checking and Intellisense
1:
2:
3:
4:
5:
6:
7:
[<Import("*","string_decoder")>]
module string_decoder =
type NodeStringDecoder =
abstract write: buffer: Buffer -> strings
abstract detectIncompleteChar: buffer: Buffer -> float
let StringDecoder: NodeStringDecoder = failwith "JS only"
Use Import attribute to import external JS modules in ES2015 fashion
- Native JS, Browser and Node interfaces are included in fable-core
- More definitions can be found in npm: fable-import-xxx
- A TypeScript parser (still in development) is also available: ts2fable
DEMO
Debugging a node express server with VS Code
1:
2:
3:
4:
5:
6:
7:
8:
{
"name": "Launch Node",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/samples/node/express/index.fsx",
"outDir": "${workspaceRoot}/samples/node/express/out",
"sourceMaps": true,
}
FABLE IN NUMBERS
- Currently in beta: v0.2.2 (soon v1.0.0)
- >600 unit tests
- >800 lines of documentation
- >4500 lines of code of compiler core
-
4 months of development (but building on FunScript experience)
- 5th place after 2 months in fsprojects (Github stars)
- >300 commits, >170 stars, 12 contributors
- 6 packages in npm: compiler, core lib, bindings, TypeScript parser
- 2500 downloads last month
- 10,000 users 2016 Q4 (1)
- 1,000,000 downloads 2016 Q4 (1)
(1) CMUF: Completely made up figures
SO WITH F# NOW YOU CAN DO...
- Front-end apps
- Node apps
- Native iOS & Android apps with Xamarin
- Mobile apps with Apache Cordova or React Native
- Universal Windows Platform (soon)
- Cross-platform desktop apps (Electron, .NET/Mono)
- Server programming: Suave, ASP.NET
- GPU programming
- Functional programming on .NET
Fable: the what, the why and the how
Bringing together the F# and JS worlds
meets