Giới thiệu dự án Goplus - Ngôn ngữ lập trình cải tiến từ Golang

Chào mọi người, mình muốn giới thiệu ý tưởng về một ngôn ngữ lập trình mới được cải tiến từ Golang, bổ sung thêm các tính năng mà Golang còn thiếu.

Nguồn cảm hứng:
Ý tưởng xuất phát từ quá trình mình học 3 ngôn ngữ: Python, Rust và Go. Mình nhận thấy các ưu và nhược điểm sau:

  • Python: Dễ học, code dễ đọc, metaprogramming ổn. Dùng FastAPI để viết API có OpenAPI tự động gen rất tiện cho vibe code ở frontend. Nhược điểm: Hiệu suất có phần đuối hơn so với Go hay Rust.
  • Go: Học rất dễ, syntax tối giản, hiệu suất thuộc top đầu (theo TechEmpower). Nhược điểm: Syntax quá tối giản dẫn đến thiếu Enum và các chức năng Macro mạnh mẽ.
  • Rust: Memory safety, siêu tối ưu, Macro mạnh mẽ. Viết API bằng Rust thực sự rất chất lượng. Nhược điểm: Đường cong học tập dốc (Steep learning curve), Macro khó sử dụng.

Mục tiêu của Goplus: Mình mong muốn có một ngôn ngữ dễ như Go nhưng sở hữu các tính năng mạnh mẽ như Rust (bỏ qua Ownership/Borrowing, sử dụng Garbage Collector cho đơn giản). Vì thế, mình đã viết một trình biên dịch bằng Rust để dịch từ Goplus sang Golang .

Các tính năng đã có ở phiên bản hiện tại:

  • Syntax: fn , struct , enum (Simple + Tagged Generic), impl .
  • Error Sugar: -> T! , -> ! , expr? .
  • Pattern Matching: match với tính năng exhaustive checking cho Enum.
  • Derive: @derive(String) cho struct/enum.
  • Compile-time decorators:
    • Built-in: @log , @retry(times[, backoff_ms]) , @memoize .
    • Custom decorators (Python-like factory style: next -> wrapped ).

Example goplus:

package main

import "fmt"

@derive(String)
enum Status {
    Pending
    Running
    Done
}

@log
@retry(3, 10)
fn readName() -> string! {
    return "goplus"
}

fn statusText(s: Status) -> string {
    match s {
        Status::Pending => "pending",
        Status::Running => "running",
        Status::Done => "done",
    }
}

fn trace(next: (fn(name: string) -> string!), label: string) -> (fn(name: string) -> string!) {
    return fn(name: string) -> string! {
        fmt.Println("trace:", label)
        return next(name)
    }
}

@trace("custom")
fn greet(name: string) -> string! {
    return "hello " + name
}

fn main() -> ! {
    name := readName()?
    fmt.Println(name)
    fmt.Println(statusText(Status::Running))

    msg := greet("goplus")?
    fmt.Println(msg)
    
    return
}

Output golang

package main

import (
	"fmt"
	"os"
	"time"
)

type Status int

const (
	StatusPending Status = iota
	StatusRunning
	StatusDone
)

func (e Status) String() string {
	switch e {
	case StatusPending:
		return "Pending"
	case StatusRunning:
		return "Running"
	case StatusDone:
		return "Done"
	default:
		return "Status(?)"
	}
}

func readName__inner() (string, error) {
	return "goplus", nil
}

func readName__decor0() (string, error) {
	var lastErr error
	for attempt := 0; attempt < 3; attempt++ {
		result, err := readName__inner()
		if err == nil {
			return result, nil
		}
		lastErr = err
		time.Sleep(time.Duration(10) * time.Millisecond)
	}
	return "", lastErr
}

func readName__decor1() (string, error) {
	fmt.Printf("[goplus] enter readName\n")
	result, err := readName__decor0()
	if err != nil {
		fmt.Printf("[goplus] error readName: %v\n", err)
		return result, err
	}
	fmt.Printf("[goplus] exit readName\n")
	return result, nil
}

func readName() (string, error) {
	return readName__decor1()
}

func statusText(s Status) string {
	switch s {
	case StatusPending:
		return "pending"
	case StatusRunning:
		return "running"
	case StatusDone:
		return "done"
	default:
		panic("unreachable")
	}
}

func trace(next func(name string) (string, error), label string) func(name string) (string, error) {
	return func(name string) (string, error) {
		fmt.Println("trace:", label)
		return next(name)
	}
}

func greet__inner(name string) (string, error) {
	return "hello " + name, nil
}

func greet__decor0(name string) (string, error) {
	decorated := trace(greet__inner, "custom")
	return decorated(name)
}

func greet(name string) (string, error) {
	return greet__decor0(name)
}

func mainWarp() error {
	name, __gp_err0 := readName()
	if __gp_err0 != nil {
		return __gp_err0
	}
	fmt.Println(name)
	fmt.Println(statusText(StatusRunning))
	msg, __gp_err1 := greet("goplus")
	if __gp_err1 != nil {
		return __gp_err1
	}
	fmt.Println(msg)
	return nil
}

func main() {
	if err := mainWarp(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?