-
Notifications
You must be signed in to change notification settings - Fork 566
XGo Class Framework Flat Mode
https://github.com/goplus/xgo/wiki/XGo-Class-Framework-Specification
Add a -flat flag to the project directive in gox.mod. In flat mode, there are no true work classfiles — instead, all matching files are fragments of the project class. Their top-level code is merged into a single _xgo_WorkMain method on the project class rather than into individual Main methods on separate work class types.
The current class framework model requires work classfiles to be structurally independent: each becomes its own Go struct with its own Main method. This works well for naturally distinct units of work (sprites, CLI commands, HTTP handlers, MCP tools), but it is not a good fit for projects that want to split a single large classfile into multiple files for organisational reasons without introducing any structural subdivision.
Flat mode addresses this gap. It allows the framework author to offer a "project-only" experience where the application developer can spread their logic across multiple files, all of which are treated as parts of one unified project class.
The -flat flag is added to the project directive:
project -flat <filePattern> <BaseType> <importPath> [extraImports...]
When -flat is present:
- The first file matching
<filePattern>is the primary project classfile (same as without-flat). Top-level code in it is compiled intoMainEntry()as usual. - All remaining files matching
<filePattern>are project fragments. They are not treated as separate work classfiles. Instead:- They share the same generated struct type as the project class (they are aliases of it, not separate types).
- Their top-level code is merged into a single method named
_xgo_WorkMainon the project class.
- No
classdirective is needed or expected when-flatis used.
Invariant:
-flatandclassdirectives are mutually exclusive within the same framework. Agox.modthat declaresproject -flatmust not also declare anyclassdirectives.
Only one struct is generated for the entire project — the project class. All fragment files contribute member declarations to this single struct. There is no second struct type.
If one or more fragment files exist, the compiler synthesises:
func (this *ProjectClass) _xgo_WorkMain() {
// top-level code from fragment file 1
// top-level code from fragment file 2
// ... in file order
}The order of fragments follows the same deterministic ordering the compiler uses for work classfiles today (typically lexicographic by filename).
If no fragment files exist (i.e. only the primary project classfile is present), _xgo_WorkMain is not generated, and nil is passed to the Template Recv Method instead.
The compiler synthesises Main on the project class as follows:
With fragment files:
func (this *ProjectClass) Main() {
XGot_<BaseType>_Main(this, this._xgo_WorkMain)
}Without fragment files:
func (this *ProjectClass) Main() {
XGot_<BaseType>_Main(this, nil)
}Unchanged from the standard case:
func main() {
new(ProjectClass).Main()
}The framework author writes:
func XGot_<BaseType>_Main(app <ProjectProto>, workMain func())-
app— the project class instance, typed as the protocol interface<ProjectProto>that the project class satisfies. -
workMain— a bound method valuethis._xgo_WorkMain, ornilwhen no fragment files are present.
The framework implementation decides when (and whether) to call workMain. A typical implementation calls it once after setup:
func XGot_MyBase_Main(app iMyProto, workMain func()) {
app.Init()
if workMain != nil {
workMain()
}
app.Run()
}To illustrate flat mode concretely, consider a framework scriptfw where the application is logically one script but can be split across files. The framework uses the dedicated suffix *.script (alternatively, *_script.gox would also be valid).
xgo 1.7
project -flat *.script ScriptApp github.com/example/scriptfw
main.script // primary project classfile
helpers.script // fragment: helper logic
tasks.script // fragment: task definitions
// Unified project struct — all files contribute to this one type
type MyProject struct {
scriptfw.ScriptApp
// member declarations from main.script, helpers.script, tasks.script
}
// From main.script — primary classfile
func (this *MyProject) MainEntry() {
// top-level code from main.script
}
// Synthesised from helpers.script + tasks.script fragments
func (this *MyProject) _xgo_WorkMain() {
// top-level code from helpers.script (in file order)
// top-level code from tasks.script
}
// Synthesised by the compiler
func (this *MyProject) Main() {
scriptfw.XGot_ScriptApp_Main(this, this._xgo_WorkMain)
}
func main() {
new(MyProject).Main()
}func XGot_ScriptApp_Main(app iScriptProto, workMain func())| Aspect | Standard mode | Flat mode (-flat) |
|---|---|---|
| Work classfiles | Each becomes its own struct type | No separate struct; all files share the project class |
| Top-level code in non-primary files | Compiled into each work class's Main()
|
Merged into _xgo_WorkMain() on the project class |
| Template Recv Method second parameter |
sprites ...Sprite / []ToolProto / etc. |
workMain func() |
class directives required |
Yes, for each work class kind | Not allowed |
-embed flag |
Applicable | Not applicable (no work classes to embed) |
| No non-primary files | Template Recv Method receives zero work instances | Template Recv Method receives nil for workMain
|
project [-flat] <filePattern> <BaseType> <importPath> [extraImports...]
class [flags] <filePattern> <BaseType> [ProtocolType]
The -flat flag is only valid on the project line. Specifying it together with any class directive in the same gox.mod is a compile-time error.
When -flat is used, <filePattern> must be a dedicated framework suffix — either a custom extension (*.spx, *.yap, *.script, …) or the *_<class>.gox form (*_script.gox, …). The bare *.gox pattern is rejected at parse time.
| Component | Change |
|---|---|
gox.mod parser |
Recognise -flat flag on project directive; reject *.gox as pattern when -flat is set |
| Classfile classifier | In flat mode, treat all <filePattern> matches as project-class fragments rather than work classfiles |
| Code generator | In flat mode, emit _xgo_WorkMain (if fragments exist) and adjust synthesised Main accordingly |
| Validation | Error if -flat and class directives coexist in one gox.mod
|
| Documentation | Update class framework reference with flat mode section |