Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: Make official embedded subset of Go specification #29147

Closed
milkowski opened this issue Dec 7, 2018 · 13 comments
Closed

proposal: Go 2: Make official embedded subset of Go specification #29147

milkowski opened this issue Dec 7, 2018 · 13 comments
Labels
FrozenDueToAge Proposal v2 A language change or incompatible library change
Milestone

Comments

@milkowski
Copy link

milkowski commented Dec 7, 2018

This is proposal to consider unifying efforts of TinyGo https://github.com/aykevl/tinygo and emgo https://github.com/ziutek/emgo projects. It would be desired to have official, standarized, subset of Go features that may by used to write compilers (or even add an option to official Go compiler itself) that are targeted for embedded devices and also that are better suited for WebAssembly use case.

Desired features would be:

  • Simpler memory model, without garbage collection, that uses predictable allocation and deallocation (preferably stack based) without need to support concurrency
  • As little runtime as possible
  • No excess data types, especially complex numbers may be omited as per proposal: spec: remove complex numbers #19921 proposal
  • Tiny basic subset of stdlib
  • More focus on efficiency of generated code than the speed of compilation itself - especially striping of dead and unused code and possible multipass analysis
@gopherbot gopherbot added this to the Proposal milestone Dec 7, 2018
@bcmills
Copy link
Contributor

bcmills commented Dec 10, 2018

Simpler memory model, without garbage collection, that uses predictable allocation and deallocation (preferably stack based) without need to support concurrency

I don't think that's a realistic goal. The Go specification and the standard library rely heavily on garbage collection.

Moreover, concurrency is fundamental to the Go programming model. (Threading is not essential, but concurrency is. Concurrency is not parallelism.)

On the other hand, it would be fine to optimize an embedded implementation to reduce the size of the runtime when garbage collection and/or concurrency are not needed. (Note that you can already use -gcflags -m to detect when and whether variables escape from the stack.)

@milkowski
Copy link
Author

You are right. By concurrency I meant some sort of nondeterministic task interleaving, but there could be deterministic task interleaving that helps manage memory heap at compile time for example.
Anyway, those are just propositions to start discussion if it makes sense and how it could be accomplished.

@4ad
Copy link
Member

4ad commented Dec 11, 2018

I wish Go would have an embedded specification (like the C standard defines both freestanding and hosted specs).

However, concurrency is an integral part of Go, and parallelism is intrinsic in almost every embedded application. Go would fare much better here than C, because it has native concurrency. Without it, embedded Go would offer little more than just a safer version of C.

Complex numbers are trivial to implement if you have floating point, but many small CPUs do not have floating point. Floating point, not merely complex numbers, need to be absent from embedded Go.

In the absence of a a garbage collector, embedded Go needs some equivalent of free(3). Stack allocation is not enough. While many embedded programs do not dynamically allocate memory, quite a few do.

@ianlancetaylor
Copy link
Contributor

It's quite difficult to define a version of Go that does not support garbage collection, as some operations in the language implicitly allocate memory. For example, converting a value to an interface type may or may not allocate memory. It's hard to see how a program could reliably release that memory allocation without being intimately aware of how the specific Go implementation works, including the details of escape analysis done by the compiler.

@4ad
Copy link
Member

4ad commented Dec 11, 2018

By default, disallow such code (compile with -+ or equivalent) and provide the programmer an explicit mechanism to do those allocations.

For embedded programming it's perfectly adequate (and expected) to depend on the specific implementation and understand how it works. It's no different than C, where you use very specific compilers and C libraries.

In embedded programming all abstractions are leaky, but they are still useful.

@ianlancetaylor
Copy link
Contributor

I think that it would be very frustrating to write Go code that did not permit implicit conversions to interface types. The majority of existing Go code could not be compiled in such an environment. You couldn't even call fmt.Print.

@beoran
Copy link

beoran commented Dec 12, 2018

A solution miight be to use automatic reference counting (ARC) in stead of a garbage collector. Sure, it has some problems in itself such for cyclycal garbage, but for OSX and Objective-C, this has proven to be a very workable solution that needs far less run-time support than a fully blown GC.

@rsc rsc added the v2 A language change or incompatible library change label Dec 12, 2018
@rsc
Copy link
Contributor

rsc commented Dec 12, 2018

There isn't enough concrete here for the proposal process. The first step would probably be for the TinyGo and emgo stakeholders to get together and try to agree on what this "subset" would be. If you agree then you could define it yourself without any permission from us at all. We don't have the active involvement in using Go for (or expertise in) embedded environments to participate meaningfully.

AppEngine effectively defined a subset of Go (no unsafe) informally, and that seemed OK.

@rsc rsc closed this as completed Dec 12, 2018
@rsc
Copy link
Contributor

rsc commented Dec 12, 2018

Note also that Go without garbage collection is essentially a new language, not really a subset.

@tredoe
Copy link

tredoe commented Feb 7, 2019

It has been created a language with a similar syntax than Go although without runtime and GC, but with easy interoperation with C and C++ (FFI in Go is pretty unfriendly).

https://volt.ws/lang

@bradleypeabody
Copy link

A little late for this issue but for the record I don't think microcontroller compatibility and garbage collection are mutually exclusive. For instance, on an embedded system a mode could exist in which the GC would only be called manually, so it could be done as applicable in a constrained environment. This does not change the language, only some runtime particulars for specific platforms.

It probably needs a new issue and a different proposed approach, but I think there is a pretty strong case that TinyGo's goals can be met without radical changes to the Go language. Indeed, TinyGo has already started to implement a basic GC. I think the issue is more than it's a heck of a lot of work to rewrite significant chunks of the runtime and optimize them for size and simplicity (instead of performance and functionality as they are now). On a microcontroller, the GC doesn't need to be fast, it needs to be small, and it needs to workable without assuming multiple threads are available.

@aykevl
Copy link

aykevl commented Aug 9, 2019

I just came across this issue, I didn't know about it before.

As the original/main TinyGo developer, my opinion is that if you were to define a subset of the Go language you might as well write a completely new language. You either are compatible with the existing Go ecosystem or you aren't - there's not much in between. Either existing packages compile with your new compiler or they don't. And I'm committed to make the TinyGo compiler compatible with the existing ecosystem as much as is reasonably possible.

To comment on a few specific issues:

  • complex numbers: leaving them out will break existing code with no real benefit. The only benefit is slightly reduced implementation complexity, but as long as you don't use them you're not paying the cost. They are now fully supported in TinyGo.

  • Garbage collection: as mentioned before there is no way to avoid this in the Go language, but how this is implemented is an implementation choice and not a language choice. TinyGo does in fact support GC on all platforms now except AVR (8-bit MCUs). The goal is to make the GC pluggable so it will be possible to make it tunable to the specific application. For example, real-time GCs are often slower but their predictability may be required for certain applications. Some applications may want to use automatic reference counting instead of tracing garbage collection, again for predictability. This is in contrast to the main Go implementation which explicitly avoids knobs on the GC. You can't define a one-size-fits-all "embedded" subset here.

  • More focus on efficiency of generated code than the speed of compilation itself - especially striping of dead and unused code and possible multipass analysis

    This is an implementation choice, not a language difference. In fact, I think the main Go implementation already has some dead code elimination at link time (similar to --gc-sections). TinyGo does dead code elimination multiple times in the compilation/linking pipeline.

  • As little runtime as possible

    This is also an implementation choice. In TinyGo, the runtime, reflect, and related packages are optimized for size instead of for speed, which is usually what you want in embedded systems.

All in all, TinyGo managed to get fmt.Println working with a custom runtime, reflect, and os package. The fmt package is the exact same you would use elsewhere. This way, we're able to get a binary size of around 50kB for the typical "hello world", which I think is remarkable when you consider how big the fmt package is and how many packages it imports.
I don't see the need for an embedded subset of Go.


If you want to know what problems we're really hitting in TinyGo, here is a slightly outdated list: https://github.com/tinygo-org/tinygo/wiki/Go-pain-points

@justinclift
Copy link

TinyGo's inclusion of volatile might be relevant as well. 😄

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge Proposal v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests