features:
- typeparams cast (#1656 goplus/gox#342 goplus/gox#344)
- overload types (#1670 #1672 goplus/gox#339 goplus/gox#340)
- overload func/method/operators (#1631 #1642 #1675 #1676 #1677 goplus/gox#355 goplus/gox#356)
- classfile: add _test.gox (a classfile for testing) (#1662 #1666 #1667 goplus/gox#348 goplus/gox#349)
- classfile: support using multiple projects (#1651)
- classfile: support Main(app, workers...) (#1653)
- stringLitEx:
${expr}
(#1636 #1637 #1646) - cl: export classNameAndExt (#1612)
- cl: set debug mark
const _ = true
(#1647 #1649 #1650) - cl: add builtin function
echo
(#1648) - Go 1.22 support (#1629 #1633)
articles:
ci/cd tools:
- build and publish winget with goreleaser (#1614 #1616 #1617 #1621 #1655)
- build deb/rpm snap (#1625 #1655)
- build Go+ demo (in $GOPROOT/testdata directory) (#1619)
changes:
- parser: fix
ParseFSEntry
for new classfile tech (#1618) - parser: fix
ParseFSDir/ParseFSEntry
set class kind if file valid (#1634) - parser: fix
parse println x...
(#1644 #1659) - parser: ast.FuncDecl add IsClass for check set recv by class (#1620)
- cl preloadGopFile optimization (#1661)
- cl preloadGopFile bugfix: pkg.SetCurFile (#1669)
- cl: toType error return types.Invalid (#1628)
- cl: instantiate use gox pkg.Instantiate (#1654)
- cl newGmx bugfix: use classNameAndExt (#1610)
- cl: call gmxMainFunc only if no main func (#1648 #1658)
- cl: NewPackage preload Go+ first and then Go files (#1630)
- ast: fix Walk ast.File if NoPkgDecl (#1624)
- ast.Walk: support OverloadFuncDecl (#1671)
- format: gop fmt .gox bugfix (#1643)
- x/typesutil: fix checker.Files skip bad file (#1623)
- x/build: use modfile.ClassExt (#1664)
- iOverloadType/iSubstType (goplus/gox#350 #1665)
- gox.Context (#1640 #1641 #1645)
Goodbye printf
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}"
Go+ Classfiles
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.
classfile: Unit Test
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
.
yap: Yet Another Go/Go+ HTTP Web Framework
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
Router and Parameters
demo (hello_yap.gox):
get "/p/:id", ctx => {
ctx.json {
"id": ctx.param("id"),
}
}
run ":8080"
Static files
Static files server demo (staticfile_yap.gox):
static "/foo", FS("public")
static "/"
run ":8080"
YAP Template
demo (blog_yap.gox, article_yap.html):
get "/p/:id", ctx => {
ctx.yap "article", {
"id": ctx.param("id"),
}
}
run ":8080"
yaptest: HTTP Test Framework
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
spx: A Go+ 2D Game Engine for STEM education
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.
Overload Func/Method/Operators in Go+
Overload Funcs
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)
Overload Methods
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)
Overload Unary Operators
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++
Overload Binary Operators
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