The Go+ programming language is designed for engineering, STEM education, and data science
highlights:
for :N { ... }
. Previously you had to use for range :N { ... }
.features:
RangeExpr
{ ... } (#1834)ci/cd tools:
changes:
highlights:
${name}
: You can customize the semantics of ${name}
. For example, in .gsh classfile, ${name}
means os.Getenv("<name>")
, and in .yap classfile, ${name}
means ctx.Param("<name>")
.YAP classfile v2
which is particularly simple and easy to use. See blow for details.features:
->
, <>
(#1763 #1764 #1766)interface{}
: rm newline (#1761 #1769 #1791)ci/cd tools:
changes:
github.com/goplus/gox
=> github.com/goplus/gogen
(#1798)YAP released v0.8.0. It introducesYAP classfile v2
which is particularly simple and easy to use. Let’s compare YAP in Go
, YAP classfile v1
and YAP classfile v2
.
demo in Go (hello.go):
import "github.com/goplus/yap"
func main() {
y := yap.New()
y.GET("/", func(ctx *yap.Context) {
ctx.TEXT(200, "text/html", `<html><body>Hello, YAP!</body></html>`)
})
y.GET("/p/:id", func(ctx *yap.Context) {
ctx.JSON(200, yap.H{
"id": ctx.Param("id"),
})
})
y.Run("localhost:8080")
}
demo in YAP classfile v1 (main.yap):
get "/", ctx => {
ctx.html `<html><body>Hello, YAP!</body></html>`
}
get "/p/:id", ctx => {
ctx.json {
"id": ctx.param("id"),
}
}
run "localhost:8080"
demo in YAP classfile v2 (get.yap, get_p_#id.yap):
html `<html><body>Hello, YAP!</body></html>`
json {
"id": ${id},
}
demo in Go (blog.go, article_yap.html):
import (
"os"
"github.com/goplus/yap"
)
y := yap.New(os.DirFS("."))
y.GET("/p/:id", func(ctx *yap.Context) {
ctx.YAP(200, "article", yap.H{
"id": ctx.Param("id"),
})
})
y.Run(":8080")
demo in YAP classfile v1 (main.yap, article_yap.html):
get "/p/:id", ctx => {
ctx.yap "article", {
"id": ctx.param("id"),
}
}
run ":8888"
demo in YAP classfile v2 (get_p_#id.yap, article_yap.html):
yap "article", {
"id": ${id},
}
See yap: Yet Another HTTP Web Framework for more details.
highlights:
classfile
to abstract domain knowledge. See Go+ Classfiles.gsh
as builtin classfile: It means now you can write shell script
in Go+. It supports all shell commands. You don't need a go.mod
file, just enter gop run XXX.gsh
directly to run. See gsh: Go+ DevOps Tools.features:
//line
before doc (#1738 #1746)//line
comments for main func (#1742 #1743).gsh
as builtin classfile (#1749)_test.gox
add App.M() (#1753)changes:
highlights:
features:
ci/cd tools:
changes:
Rob Pike once said that if he could only introduce one feature to Go, he would choose interface
instead of goroutine
. classfile
is as important to Go+ as interface
is to Go.
In the design philosophy of Go+, we do not recommend DSL
(Domain Specific Language). But SDF
(Specific Domain Friendliness) is very important. The Go+ philosophy about SDF
is:
Don't define a language for specific domain.
Abstract domain knowledge for it.
Go+ introduces classfile
to abstract domain knowledge.
Sound a bit abstract? Let's take web programming as an example. First let us initialize a hello project:
gop mod init hello
Then we have it reference a classfile called yap
as the HTTP Web Framework:
gop get github.com/goplus/yap@latest
We can use it to implement a static file server:
static "/foo", FS("public")
static "/" # Equivalent to static "/", FS("static")
run ":8080"
We can also add the ability to handle dynamic GET/POST requests:
static "/foo", FS("public")
static "/" # Equivalent to static "/", FS("static")
get "/p/:id", ctx => {
ctx.json {
"id": ctx.param("id"),
}
}
run ":8080"
Save this code to hello_yap.gox
file and execute:
mkdir -p yap/static yap/public # Static resources can be placed in these directories
gop mod tidy
gop run .
A simplest web program is running now. At this time, if you visit http://localhost:8080/p/123, you will get:
{"id":"123"}
Why is yap
so easy to use? How does it do it? Click here to learn more about the Go+ Classfiles mechanism and YAP HTTP Web Framework.
features:
articles:
ci/cd tools:
changes:
features:
${expr}
(#1636 #1637 #1646)const _ = true
(#1647 #1649 #1650)echo
(#1648)articles:
ci/cd tools:
changes:
ParseFSEntry
for new classfile tech (#1618)ParseFSDir/ParseFSEntry
set class kind if file valid (#1634)parse println x...
(#1644 #1659)For professional programmers, printf
is a very familiar function, and it can be found in basically every language. However, printf
is one of the most difficult functions for beginners to master:
age := 10
printf "age = %d\n", age
Here %d
means to format an integer value and \n
means a newline.
To simplify format information in most cases, Go+ introduces ${expr}
expressions in string literals:
age := 10
println "age = ${age}"
This is a bit like how you feel at the *nix
command line, right? To be more like it, we introduced a new builtin echo
as an alias for println
:
age := 10
echo "age = ${age}"
Rob Pike once said that if he could only introduce one feature to Go, he would choose interface
instead of goroutine
. classfile
is as important to Go+ as interface
is to Go.
In the design philosophy of Go+, we do not recommend DSL
(Domain Specific Language). But SDF
(Specific Domain Friendliness) is very important. The Go+ philosophy about SDF
is:
Don't define a language for specific domain.
Abstract domain knowledge for it.
Go+ introduces classfile
to abstract domain knowledge.
Go+ has a built-in classfile to simplify unit testing. This classfile has the file suffix _test.gox
.
Suppose you have a function named foo
:
func foo(v int) int {
return v * 2
}
Then you can create a foo_test.gox
file to test it (see unit-test/foo_test.gox):
if v := foo(50); v != 100 {
t.error "foo(50) ret: ${v}"
}
t.run "foo -10", t => {
if foo(-10) != -20 {
t.fatal "foo(-10) != -20"
}
}
You don't need to define a series of TestXXX
functions like Go, just write your test code directly.
If you want to run a subtest case, use t.run
.
This classfile has the file suffix _yap.gox
.
Before using yap
, you need to add it to go.mod
by using go get
:
go get github.com/goplus/yap@latest
Find require github.com/goplus/yap
statement in go.mod
and add //gop:class
at the end of the line:
require github.com/goplus/yap v0.7.2 //gop:class
demo (hello_yap.gox):
get "/p/:id", ctx => {
ctx.json {
"id": ctx.param("id"),
}
}
run ":8080"
Static files server demo (staticfile_yap.gox):
static "/foo", FS("public")
static "/"
run ":8080"
demo (blog_yap.gox, article_yap.html):
get "/p/:id", ctx => {
ctx.yap "article", {
"id": ctx.param("id"),
}
}
run ":8080"
This classfile has the file suffix _ytest.gox
.
Before using yaptest
, you need to add yap
to go.mod
:
require github.com/goplus/yap v0.7.2 //gop:class
demo to test your HTTP server (example_ytest.gox):
title := Var(string)
author := Var(string)
id := "123"
get "https://example.com/p/${id}"
ret 200
json {
"title": title,
"author": author,
}
echo "title:", title
echo "author:", author
This classfile has the file suffix .spx
. It is the earliest classfile in the world.
Before using spx
, you need to add it to go.mod
by using go get
:
go get github.com/goplus/spx@latest
It's also a built-in classfile so you don't need append //gop:class
after require github.com/goplus/spx
.
Through this example you can learn how to listen events and do somethings.
Here are some codes in Kai.spx:
onStart => {
say "Where do you come from?", 2
broadcast "1"
}
onMsg "2", => {
say "What's the climate like in your country?", 3
broadcast "3"
}
We call onStart
and onMsg
to listen events. onStart
is called when the program is started. And onMsg
is called when someone calls broadcast
to broadcast a message.
When the program starts, Kai says Where do you come from?
, and then broadcasts the message 1
. Who will recieve this message? Let's see codes in Jaime.spx:
onMsg "1", => {
say "I come from England.", 2
broadcast "2"
}
Yes, Jaime recieves the message 1
and says I come from England.
. Then he broadcasts the message 2
. Kai recieves it and says What's the climate like in your country?
.
The following procedures are very similar. In this way you can implement dialogues between multiple actors.
Define overload func
in inline func literal
style (see overloadfunc1/add.gop):
func add = (
func(a, b int) int {
return a + b
}
func(a, b string) string {
return a + b
}
)
println add(100, 7)
println add("Hello", "World")
Define overload func
in ident
style (see overloadfunc2/mul.gop):
func mulInt(a, b int) int {
return a * b
}
func mulFloat(a, b float64) float64 {
return a * b
}
func mul = (
mulInt
mulFloat
)
println mul(100, 7)
println mul(1.2, 3.14)
Define overload method
(see overloadmethod/method.gop):
type foo struct {
}
func (a *foo) mulInt(b int) *foo {
println "mulInt"
return a
}
func (a *foo) mulFoo(b *foo) *foo {
println "mulFoo"
return a
}
func (foo).mul = (
(foo).mulInt
(foo).mulFoo
)
var a, b *foo
var c = a.mul(100)
var d = a.mul(c)
Define overload unary operator
(see overloadop1/overloadop.gop):
type foo struct {
}
func -(a foo) (ret foo) {
println "-a"
return
}
func ++(a foo) {
println "a++"
}
var a foo
var b = -a
a++
Define overload binary operator
(see overloadop1/overloadop.gop):
type foo struct {
}
func (a foo) * (b foo) (ret foo) {
println "a * b"
return
}
func (a foo) != (b foo) bool {
println "a != b"
return true
}
var a, b foo
var c = a * b
var d = a != b
However, binary operator
usually need to support interoperability between multiple types. In this case it becomes more complex (see overloadop2/overloadop.gop):
type foo struct {
}
func (a foo) mulInt(b int) (ret foo) {
println "a * int"
return
}
func (a foo) mulFoo(b foo) (ret foo) {
println "a * b"
return
}
func intMulFoo(a int, b foo) (ret foo) {
println "int * b"
return
}
func (foo).* = (
(foo).mulInt
(foo).mulFoo
intMulFoo
)
var a, b foo
var c = a * 10
var d = a * b
var e = 10 * a
Ignore this release please. This is only a release tool test.
features:
_[class].gox
or .[class]
(#1606 https://github.com/goplus/mod/pull/42)//gop:class
to import a classfile (#1607 https://github.com/goplus/mod/pull/45)changes:
demo in Go+ classfile (hello_yap.gox):
get "/p/:id", ctx => {
ctx.json {
"id": ctx.param("id"),
}
}
handle "/", ctx => {
ctx.html `<html><body>Hello, <a href="/p/123">Yap</a>!</body></html>`
}
run ":8080"
demo in Go+ classfile (blog_yap.gox, article.yap):
get "/p/:id", ctx => {
ctx.yap "article", {
"id": ctx.param("id"),
}
}
run ":8080"
new features:
//line
path (#1553 #1552 #1557)tinygo example:
GOP_GOCMD=tinygo gop run hello.gop
changes:
new features:
github actions:
changes: