Welcome to lgo

This notebook demostrates the basic usage of lgo. You can use all Go (golang) language features with lgo.

More examples

After you learn this notebook, see these notebooks to understand advanced topics.

Environments

Displays the environment where this notebook is executed.

In [ ]:
import (
    "fmt"
    "os"
    "os/user"
    "runtime"
)

{
    user, _ := user.Current()
    fmt.Printf("Go: %s (%s_%s)\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
    fmt.Printf("User: %s\n", user.Username)
    wd, _ := os.Getwd()
    fmt.Printf("Working dir: %s\n", wd)
    fmt.Printf("NumCPU: %d\n", runtime.NumCPU())
}
Go: go1.9.2 (linux_amd64)
User: gopher
Working dir: /examples
NumCPU: 2

Simple functions

In [ ]:
// naiveFib calculates the n-th fibonacci number
func naiveFib(n int) int {
    if n > 1 {
        return naiveFib(n - 1) + naiveFib(n - 2)
    }
    return 1
}
In [ ]:
naiveFib(20)
10946

if, for, etc..

In [ ]:
import "fmt"

n := 10

if n > 0 {
    fmt.Println("n is positive:", n)
} else {
    fmt.Println("n is not positive:", n)
}
n is positive: 10
In [ ]:
sum := 0
for i := 1; i <= n; i++ {
    sum += i
}
sum
55
In [ ]:
switch sum {
case 55:
    fmt.Println("OK")
default:
    fmt.Println("Fail")
}
OK

Use standard libraries

In [ ]:
import (
    "fmt"
    "math"
)
In [ ]:
fmt.Printf("sin(pi/3) == %f\n", math.Sin(math.Pi/3))
fmt.Printf("cos(pi/3) == %f\n", math.Cos(math.Pi/3))
fmt.Printf("sqrt(3)/2 == %f\n", math.Sqrt(3)/2)
fmt.Printf("log(e^2) == %f\n", math.Log(math.E * math.E))
sin(pi/3) == 0.866025
cos(pi/3) == 0.500000
sqrt(3)/2 == 0.866025
log(e^2) == 2.000000
21
<nil>

Non-deterministic code

In [ ]:
import (
    "math/rand"
    "time"
)
In [ ]:
rand.Seed(time.Now().UnixNano())
r := rand.Int()
r
636250466556259171
In [ ]:
r % 10000
9171
In [ ]:
start := time.Now()
start
2017-10-16 13:17:47.637999781 +0000 UTC m=+6.138424087
In [ ]:
end := time.Now()
end
2017-10-16 13:17:48.311503905 +0000 UTC m=+6.811928266
In [ ]:
fmt.Printf("end - start = %v", end.Sub(start))
end - start = 673.504179ms26
<nil>

struct and interface

In [ ]:
type person struct {
    name string
    age int
}

func (p *person) Hello() string {
    return fmt.Sprintf("Hello! Name: %s, Age: %d", p.name, p.age)
}
In [ ]:
p := person{"Alice", 12}
fmt.Printf("p.name = %q\n", p.name)
fmt.Printf("p.Hello() == %q\n", p.Hello())
p.name = "Alice"
p.Hello() == "Hello! Name: Alice, Age: 12"
43
<nil>
In [ ]:
type hello interface {
    Hello() string
}

func printHello(h hello) {
    if _, ok := h.(*person); ok {
        fmt.Println("h is *person")
    }
    fmt.Printf("h.Hello() == %q\n", h.Hello())
}

p := person{"Alice", 12}
printHello(&p)
h is *person
h.Hello() == "Hello! Name: Alice, Age: 12"

Go libraries and interfaces

Of course, you can interacts with Go libraries using interfaces

In [ ]:
// You can pass a type defined in lgo as an interface defined in Go.

import (
    "bytes"
    "fmt"
    "io"
)

type myReader struct {
    content string
    idx int
}

func (r *myReader) Read(p []byte) (n int, err error) {
    if len(p) == 0 {
        return 0, nil
    }
    if r.idx >= len(r.content) {
        return 0, io.EOF
    }
    p[0] = r.content[r.idx]
    fmt.Printf("Read %q\n", r.content[r.idx])
    r.idx++
    return 1, nil
}

{
    r := myReader{content: "Hello!"}
    var buf bytes.Buffer
    io.Copy(&buf, &r)
    fmt.Printf("buf == %q\n", buf.String())
}
Read 'H'
Read 'e'
Read 'l'
Read 'l'
Read 'o'
Read '!'
buf == "Hello!"
In [ ]:
// You can pass a struct defined in Go as an interface defined in lgo too.

import (
    "bytes"
    "fmt"
)

type withLen interface {
    Len() int
}

func printLen(l withLen) {
    fmt.Printf("Len(%v) == %d\n", l, l.Len())
}

{
    var buf bytes.Buffer
    buf.WriteString("01234")
    printLen(&buf)
    buf.WriteString("56789")
    printLen(&buf)
}
Len(01234) == 5
Len(0123456789) == 10

return & defer

A code block in lgo is executed code inside a function with no return value. You can exit code by return statement. Also, you can use defer to execute functions after a code block.

In [ ]:
// return
if true {
    fmt.Println("return!")
    return
}
fmt.Println("continue!")
return!
In [ ]:
fmt.Println("start")
defer fmt.Println("defer (1)")
defer fmt.Println("defer (2)")
fmt.Println("end")
start
end
4
<nil>
defer (2)
defer (1)

channel and goroutine

In [ ]:
import "fmt"

{
    done := make(chan struct{})
    ch := make(chan int)
    // producer
    go func(){
        for i := 0; i < 10; i++ {
            ch <- i * i
        }
        close(ch)
    }()
    // consumer
    go func() {
        for i := range ch {
            fmt.Printf("i == %d\n", i)
        }
        close(done)
    }()
    <-done
}
i == 0
i == 1
i == 4
i == 9
i == 16
i == 25
i == 36
i == 49
i == 64
i == 81

panic

In [ ]:
panic("failed!")
panic: failed!

goroutine 41 [running]:
runtime/debug.Stack(0xc400000008, 0x7f257d12a338, 0xc4204301a0)
	/usr/lib/go-1.9/src/runtime/debug/stack.go:24 +0xa9
github.com/yunabe/lgo/core.(*resultCounter).recordResult(0xc420430188, 0x7f257cf4f140, 0x7f25705f3970)
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:182 +0xce
github.com/yunabe/lgo/core.(*resultCounter).recordResultInDefer(0xc420430188)
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:187 +0x3b
panic(0x7f257cf4f140, 0x7f25705f3970)
	/usr/lib/go-1.9/src/runtime/panic.go:491 +0x294
github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec3.lgo_init()
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec3/src.go:6 +0x40
github.com/yunabe/lgo/cmd/runner.loadShared.func3()
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/cmd/runner/runner.go:60 +0x26
github.com/yunabe/lgo/core.newRoutineManager.func1(0xc420430180, 0xc42042aad0)
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:205 +0x83
created by github.com/yunabe/lgo/core.newRoutineManager
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:202 +0xc5
main routine failed
In [ ]:
go func() {
    panic("goroutine failed")
}()
panic: goroutine failed

goroutine 67 [running]:
runtime/debug.Stack(0xc400000008, 0x7f257d12a338, 0xc4204181c0)
	/usr/lib/go-1.9/src/runtime/debug/stack.go:24 +0xa9
github.com/yunabe/lgo/core.(*resultCounter).recordResult(0xc4204181a8, 0x7f257cf4f140, 0x7f25703ef760)
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:182 +0xce
github.com/yunabe/lgo/core.FinalizeGoroutine(0xc42032e2c0)
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:283 +0x4f
panic(0x7f257cf4f140, 0x7f25703ef760)
	/usr/lib/go-1.9/src/runtime/panic.go:491 +0x294
github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4.lgo_init.func1.1()
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4/src.go:12 +0x40
github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4.lgo_init.func1(0xc42032e2c0)
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4/src.go:13 +0x4a
created by github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4.lgo_init
	/home/yunabe/local/gocode/src/github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4/src.go:8 +0x4a
1 goroutine failed

reflect

reflect package works with lgo properly. Note that unexported fields are renamed with LgoExport_ prefix in lgo.

In [ ]:
import (
    "reflect"
)

type person struct {
    Name string
    Age int
    secret string
}

func (p *person) GetSecret() string {
    return p.secret
}

p := &person{Name:"Alice", Age: 12, secret: "1234"}
In [ ]:
{
    t := reflect.TypeOf(p)
    fmt.Println("--- fields ---")
    for i := 0; i < t.Elem().NumField(); i++ {
        fmt.Printf("field[%d] = %s\n", i, t.Elem().Field(i).Name)
    }
    
    fmt.Println("--- methods ---")
    for i := 0; i < t.NumMethod(); i++ {
        fmt.Printf("method[%d] = %s\n", i, t.Method(i).Name)
    }

    // Set "Age" via reflect.
    v := reflect.ValueOf(p)
    v.Elem().Field(1).Set(reflect.ValueOf(34))
    
    fmt.Println("------------")
    fmt.Printf("p == %#v\n", p)
}
--- fields ---
field[0] = Name
field[1] = Age
field[2] = LgoExport_secret
--- methods ---
method[0] = GetSecret
------------
p == &lgo_exec.LgoExport_person{Name:"Alice", Age:34, LgoExport_secret:"1234"}

Display

To display non-text content like HTML, MarkDown and images, use _ctx.Display.

In [ ]:
// Display HTML
_ctx.Display.HTML(
    `Hello <b>lgo</b>: <a target="_blank" href="https://github.com/yunabe/lgo" >GitHub lgo</a>
<div style="width:50px;height:50px;background-color:red"></div>`,
    nil)
Hello lgo: GitHub lgo
In [ ]:
import (
    "fmt"
    "io/ioutil"
    "net/http"    
)

var gopherPNG []byte
{
    res, err := http.Get("https://golang.org/doc/gopher/frontpage.png")
    if err != nil {
        fmt.Printf("Failed to get: %v\n", err)
        return
    }
    defer res.Body.Close()
    gopherPNG, err = ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Printf("Failed to read: %v\n", err)
        return
    }
    _ctx.Display.Text("PNG Gopher", nil)
    _ctx.Display.PNG(gopherPNG, nil)
}
PNG Gopher
In [ ]:
import (
    "bytes"
    "image"
    jpeg "image/jpeg"
    _ "image/png"
    "os"
    
    "github.com/nfnt/resize"
)

{
    img, _, err := image.Decode(bytes.NewBuffer(gopherPNG))
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to decode: %v", err)
        return
    }
    img = resize.Resize(100, 0, img, resize.Lanczos3)
    var buf bytes.Buffer
    jpeg.Encode(&buf, img, &jpeg.Options{Quality: 1})
    _ctx.Display.Text("Resized and highly compressed JPEG", nil)
    _ctx.Display.JPEG(buf.Bytes(), nil)
}
Resized and highly compressed JPEG

Display ID

You can use the second paramter of display methods to overwrite the existing results. See DataDisplayer for details.

In [ ]:
import (
    "bytes"
    "fmt"
    "image"
    png "image/png"
    jpeg "image/jpeg"
    "os"
    "time"
    
    "github.com/nfnt/resize"
)

{
    img, err := png.Decode(bytes.NewBuffer(gopherPNG))
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to decode:", err)
        return
    }
    img = resize.Resize(100, 0, img, resize.Lanczos3)
    var labelID, imgID string
    for quality := 25; quality > 0; quality -= 1 {
        var buf bytes.Buffer
        jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality})
        size := float32(len(buf.Bytes()))/1000
        _ctx.Display.Text(fmt.Sprintf("Quality: %d\nSize: %.2fkB", quality, size), &labelID)
        _ctx.Display.JPEG(buf.Bytes(), &imgID)
        time.Sleep(200*time.Millisecond)
    }
}
Quality: 1
Size: 1.28kB

Compile errors

syntax errors

In [ ]:
{
    x := 10 + 3.4 +
}
{
    for i := 0 {}
}
3:1: expected operand, found '}'
5:5: expected ';', found 'for'

type errors

In [ ]:
{  // L.1
    a := undefined
    
    x := 10
    y := 3.4  // L.5
    z := x + y

    unused := 10
    
    for i := 0; i; i++ {}  // L.10
    
    _, _ = a, z
}
2:10: undeclared name: undefined
6:10: invalid operation: mismatched types int and float64
10:17: non-boolean condition in for statement
8:5: unused declared but not used