-
Notifications
You must be signed in to change notification settings - Fork 382
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
META - splitting and refactoring std
#1475
Comments
"std"
package naming
I'm with the opinion to avoid overwriting any existing Go stdlib package names to avoid confusing: those who often switch between the languages, the searchability within the codebase (as I don't think renaming this library is necessary but I'm curious to hear what others think; or we can determine as a collective rather how to refer to the current |
I have experienced similar feelings on multiple occasions. Here are my current ideas, listed randomly:
|
With 1. we will need workarounds in order to discuss/document the std package (not that big of a deal, but still), so essentially I am for modifying the name. I believe 2. is a totally valid concern. I think Are there any technical challenges in regarding to doing this kind of renaming? |
I can't see any significant technical challenges. It's primarily a challenge related to language design and concerns about adoption and documentation. Remember that it will be the most widely used import. It's kind of similar with choosing the right keyword, like "return," "panic," "switch," or "for,". It should be something memorable, similar to the well-known |
I like the name I think it is better to keep it out of the normal "userland" package space because of the native bindings that it is built on. I think it makes sense in general for ONLY standard library packages to be able to define native bindings. And in fact, now that the native bindings PR has been merged, it ensures that they are only supported in standard library packages. So TLDR; I don't support renaming this package but am fine with reorganizing into subpackages.
|
I largely second others in thinking that putting I don't like I propose the following (sorry, I detoured on a redesign of all of the function names, hope you'll forgive me):
In other words, I like to have a package In a kind of way, this is similar to package |
Also, one more thought. I'd reserve Maybe the way we implement goroutines is different enough that a better fit is to change the keyword entirely to |
Similar to syscall/js |
Let this comment be a poll: Idea 1: as per @thehowl's comment, split Idea 2: simply rename Idea 3: keep In addition, I think that no matter the case, we should decouple classic |
Merge order: 1. #1700 2. #1702 3. #1695 (this one!) -- review earlier ones first, if they're still open! This PR modifies the Gno transpiler (fka precompiler) to use Gno's standard libraries rather than Go's when performing transpilation. This creates the necessity to transpile Gno standard libraries, and as such support their native bindings. And it removes the necessity for a package like `stdshim`, and a mechanism like `stdlibWhitelist`. - Fixes #668. Fixes #1865. - Resolves #892. - Part of #814. - Makes #1475 / #1576 possible without using hacks like `stdshim`. cc/ @leohhhn @tbruyelle, as this relates to your work ## Why? - This PR enables us to perform Go type-checking across the board, and not use Go's standard libraries in transpiled code. This enables us to _properly support our own standard libraries_, such as `std` but any others we might want or need. - It also paves the way further to go full circle, and have Gno code be transpiled to Go, and then have "compilable" gno code ## Summary of changes - The transpiler has been thoroughly refactored. - The biggest change is described above: instead of maintaing the import paths like `"strconv"` and `"math"` the same (so using Gno's stdlibs in Gno, and Go's in Go), the import paths for standard libraries is now also updated to point to the Gno standard libraries. - Native functions are handled by removing their definitions when transpiling, and changing their call expressions where appropriate. This links the transpiled code directly to their native counterparts. - This removes the necessity for `stdlibWhitelist`. - As a consequence, `stdshim` is no longer needed and has been removed. - Test files are still not "strictly checked": they may reference stdlibs with no matching source, and will not be tested when running with `--gobuild`. This is because packages like `fmt` have no representation in Gno code; they only exist as injections in `tests/imports.go`. I'll fix this eventually :) - The CLI (`gno transpile`) has been changed to reflect the above changes. - Flag `--skip-fmt` has been removed (the result of transpile is always formatted, anyway), and `--gofmt-binary` too, obviously. `gno transpile` does not perform validation, but will gladly provide helpful validation with the `--gobuild` flag. - There is another PR that adds type checking in `gno lint`, without needing to run through the transpilation step first: #1730 - It now works by default by looking at "packages" rather than individual files. This is necessary so that when performing `transpile` on the `examples` directory, we can skip those where the gno.mod marks the module as draft. These modules make use of packages like "fmt", which because they don't have an underlying gno/go source, cannot be transpiled. - Running with `-gobuild` now handles more errors correctly; ie., all errors not previously captured by the `errorRe` which only matches those pertaining to a specific file/line. - `gnoFilesFromArgs` was unused and as such deleted - `gnomod`'s behaviour was slightly changed. - I am of the opinion that `gno mod download` should not precompile what it downloads; _especially_ to gather the dependencies it has. I've changed it so that it does a `OnlyImports` parse of the file it downloads to fetch additional dependencies Misc: - `Makefile` now contains a recipe to calculate the coverage for `gnovm/cmd/gno`, and also view it via the HTML interface. This is needed as it has a few extra steps (which @gfanton already previously added in the CI). - Realms r/demo/art/gnoface and r/x/manfred_outfmt have been marked as draft, as they depend on packages which are not actually present in the Gno standard libraries. - The transpiler now ignores draft packages by default. - `ReadMemPackage` now also considers Go files. This is meant to have on-chain the code for standard libraries like `std` which have native bindings. We still exclude Go code if it's not in a standard library. - `//go:build` constraints have been removed from standard libraries, as go files can only have one and we already add our own when transpiling ## Further improvements after this PR - Scope understanding in `transpiler` (so call expressions are not incorrectly rewritten) - Correctly transpile gno.mod --------- Co-authored-by: Antonio Navarro Perez <[email protected]> Co-authored-by: Miloš Živković <[email protected]>
I simply advocate renaming I do agree splitting packages makes sense as possible solution1, however people are not only going to program exclusively in gno in the future. Beginners (in gno) and nobody else are the ones who will become long-term users, and for that conversion rate to be maximized I think they need a simple language.
About reserving
|
Merge order: 1. gnolang#1700 2. gnolang#1702 3. gnolang#1695 (this one!) -- review earlier ones first, if they're still open! This PR modifies the Gno transpiler (fka precompiler) to use Gno's standard libraries rather than Go's when performing transpilation. This creates the necessity to transpile Gno standard libraries, and as such support their native bindings. And it removes the necessity for a package like `stdshim`, and a mechanism like `stdlibWhitelist`. - Fixes gnolang#668. Fixes gnolang#1865. - Resolves gnolang#892. - Part of gnolang#814. - Makes gnolang#1475 / gnolang#1576 possible without using hacks like `stdshim`. cc/ @leohhhn @tbruyelle, as this relates to your work ## Why? - This PR enables us to perform Go type-checking across the board, and not use Go's standard libraries in transpiled code. This enables us to _properly support our own standard libraries_, such as `std` but any others we might want or need. - It also paves the way further to go full circle, and have Gno code be transpiled to Go, and then have "compilable" gno code ## Summary of changes - The transpiler has been thoroughly refactored. - The biggest change is described above: instead of maintaing the import paths like `"strconv"` and `"math"` the same (so using Gno's stdlibs in Gno, and Go's in Go), the import paths for standard libraries is now also updated to point to the Gno standard libraries. - Native functions are handled by removing their definitions when transpiling, and changing their call expressions where appropriate. This links the transpiled code directly to their native counterparts. - This removes the necessity for `stdlibWhitelist`. - As a consequence, `stdshim` is no longer needed and has been removed. - Test files are still not "strictly checked": they may reference stdlibs with no matching source, and will not be tested when running with `--gobuild`. This is because packages like `fmt` have no representation in Gno code; they only exist as injections in `tests/imports.go`. I'll fix this eventually :) - The CLI (`gno transpile`) has been changed to reflect the above changes. - Flag `--skip-fmt` has been removed (the result of transpile is always formatted, anyway), and `--gofmt-binary` too, obviously. `gno transpile` does not perform validation, but will gladly provide helpful validation with the `--gobuild` flag. - There is another PR that adds type checking in `gno lint`, without needing to run through the transpilation step first: gnolang#1730 - It now works by default by looking at "packages" rather than individual files. This is necessary so that when performing `transpile` on the `examples` directory, we can skip those where the gno.mod marks the module as draft. These modules make use of packages like "fmt", which because they don't have an underlying gno/go source, cannot be transpiled. - Running with `-gobuild` now handles more errors correctly; ie., all errors not previously captured by the `errorRe` which only matches those pertaining to a specific file/line. - `gnoFilesFromArgs` was unused and as such deleted - `gnomod`'s behaviour was slightly changed. - I am of the opinion that `gno mod download` should not precompile what it downloads; _especially_ to gather the dependencies it has. I've changed it so that it does a `OnlyImports` parse of the file it downloads to fetch additional dependencies Misc: - `Makefile` now contains a recipe to calculate the coverage for `gnovm/cmd/gno`, and also view it via the HTML interface. This is needed as it has a few extra steps (which @gfanton already previously added in the CI). - Realms r/demo/art/gnoface and r/x/manfred_outfmt have been marked as draft, as they depend on packages which are not actually present in the Gno standard libraries. - The transpiler now ignores draft packages by default. - `ReadMemPackage` now also considers Go files. This is meant to have on-chain the code for standard libraries like `std` which have native bindings. We still exclude Go code if it's not in a standard library. - `//go:build` constraints have been removed from standard libraries, as go files can only have one and we already add our own when transpiling ## Further improvements after this PR - Scope understanding in `transpiler` (so call expressions are not incorrectly rewritten) - Correctly transpile gno.mod --------- Co-authored-by: Antonio Navarro Perez <[email protected]> Co-authored-by: Miloš Živković <[email protected]>
I appreciate the "natural feeling" given by typing out This is similar to what happens in go; where the
What? People aren't going to programming exclusively for gno.land in the future. But this is a change that concerns primarily the standard libraries, which are likely to be brought over into other gno.land ecosystems. This actually strengthens my argument; that
good rhetoric ;) i don't think we'll necessarily end up using it as a keyword; it's a backward-incompatible change with go, i'd much rather use but from principles, i disagree that |
Related issues, to discuss as a single solution |
Tentative reorganization: https://gist.github.com/moul/f28f4b12864fd40a2ca6b6c20294da27 |
"std"
package naming
Combining all the proposals into the top-level comment of this issue |
Updated the top-level comment to centralize all proposals. @moul Please take a look; I tried to summarize also the changes that I tried making with #2425 so that they can be tackled by someone other than me, as we talked about. What do you think about having a call to go through all of these and figuring out what proposals are sensible and to act on? I think we can work on these in small PRs, but possibly do all breaking changes ahead of test6. As a side note, I added the |
std
Let's schedule a call. Initially, I expected to create a PR instead of this issue so we could comment line by line. However, the problem is that each proposal will not only change lines but also file locations. Therefore, let's have a call. Regarding whether to create a single PR or multiple ones, my main concern is fixing the history of the portal loop. This depends on #3024 as evidence that we can patch the history for such breaking changes. Let's assume it will be ready, but we rely not only on developers but also on DevOps to ensure the portal loop loads the Git state. Alternatively, if @gfanton can make gnodev the next portal loop with this feature, that could also work. |
Thursday called; reached full consensus on the first three proposals. For the fourth, "Remove std.GetOrigCaller and std.IsOriginCall", let's come back at it next week with more usage examples (both in favour and against the inclusion of the two functions). |
Here are my two cents:
|
fix #2107 -------------------------- ## Problem > From [#875 (review)](#875 (review)): > > > That said, soon after this is merged, I think we'll need to change this API again. This current implementation creates an inconsistency within the Banker API. All other banker methods now require you to pass in the full realm path to the token you're referring to, but IssueCoin and RemoveCoin do not. > > Thus, I think a few more changes are in order: > > > > 1. There should be a `RealmDenom(pkgpath, denom string)` function in `std`, which creates a realm denomination (ie. `/gno.land/r/morgan:bitcoin`). There can be a helper method `Realm.Denom(denom string)` (so you can do `std.CurrentRealm().Denom("bitcoin")` > > 2. Instead of modifying `denom`'s value in the native function, we should check it matches what we expect. ie. `strings.HasPrefix(denom, RealmDenom(std.CurrentRealm().PkgPath())`, then check the last part of the denom to see that it matches the Gno regex. (This can all be done in gno, without needing to put it in native code) > > Related with #1475 #1576 ------------------------- ## Solution BREAKING CHANGE: All previous realm calling IssueCoin or RemoveCoin are now expected to append the prefix "/" + realmPkgPath + ":" before the denom, it should be done by using ``std.CurrentRealm().CoinDenom(denom string)`` or by using ``std.CoinDenom(pkgPath, denom string)`` For now to avoid to mix coins and fix security issues like being able to issue coins from other realm, when a realm issue a coin, the pkg path of the realm is added as a prefix to the coin. the thing is some function expect only the base denom ``bitcoin`` (issue & remove) but the others like get require the qualified denom ``gno.land/r/demo/banktest:bitcoin``. it can be confusing I also answer the requirements of the comment @thehowl made: - Two functions are now available ``std.CoinDenom(pkgpath, demon string)`` && the method ``std.Realm.CoinDenom(denom string)`` - the denom's value is changed in the `.gno` file and not the native. Here is an example of how it looks like: ```go func IssueNewCoin(denom string, amount int64) string { std.AssertOriginCall() banker := std.GetBanker(std.BankerTypeRealmIssue) addr := std.PrevRealm().Addr() banker.IssueCoin(addr, std.CurrentRealm().CoinDenom(denom), amount) return std.CurrentRealm().Denom(denom) } func RemoveCoin(denom string, amount int64) { std.AssertOriginCall() banker := std.GetBanker(std.BankerTypeRealmIssue) addr := std.PrevRealm().Addr() banker.RemoveCoin(addr, std.CurrentRealm().CoinDenom(denom), amount) } func GetCoins(denom string) uint64 { banker := std.GetBanker(std.BankerTypeReadonly) addr := std.PrevRealm().Addr() coins := banker.GetCoins(addr) for _, coin := range coins { if coin.Denom == std.CurrentRealm().CoinDenom(denom) { return uint64(coin.Amount) } } return 0 } ``` <details><summary>Contributors' checklist...</summary> - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests </details> --------- Co-authored-by: Morgan Bazalgette <[email protected]> Co-authored-by: Leon Hudak <[email protected]>
This is a META issue centralizing the current state of proposals on how to re-organize the
std
standard library.List of proposals
Collected by @thehowl, with reasons and statuses attempted to be summarized by him and possibly incorrect, but all to the best of his knowledge / research.
Split into different packages
Package name ideas (see related gist
chain
- containing critical chain types, likeAddress
,AddressList
.chain/runtime
- containing meta-VM functions, likeCurrentRealm
,PrevRealm
,AssertOriginCall
.runtime
as it has a different API and usage than Go'sruntime
chain/banker
- containing theBanker
andCoin
types, and related functions and methods to deal with the native banker.chain/params
- containing theSetParamBool
,SetParamString
,...
typesThe division into packages should help to reduce the scope of each package, helping us create modular packages. It's not definitive; some questions remain on where to put the
Emit
functions.Why: at the time being, all Gno-specific functions are lumped together in a single, big
std
package. Naming packages like base, util or common is considered bad practice in Go, where instead packages should be more specific and be concerned with specific purposes.Status: consensus.
References:
std
#1475 (comment)std
#1475 (comment)Removing
Get
prefixes from the functionsWhy: Effective Go states that "there's nothing wrong with providing getters and setters yourself, and it's often appropriate to do so, but it's neither idiomatic nor necessary to put
Get
into the getter's name."Status: consensus.
References:
std
API #848std
package API more user-friendly #1576Expanding abbreviations and using consistent naming
std
currently has a variety of places where it usesAddr
and others where it usesAddress
, and other similar abbreviations listed above. The most important thing is to make everything consistent; the proposed way of doing so is by preferring the expanded version.NOTE: we should keep
Pkg
as it is instead ofPackage
, asPkgPath
is used in many other places and is already established as a "conventional abbreviation".Why: using consistent naming allows us to avoid becoming the next PHP.
Status: consensus.
References:
std
#1475 (comment)std
package API more user-friendly #1576Remove
std.IsOriginCall
Why:
IsOriginCall
, is a function that should likely not be used and available to end-users. It only serves to check that the function calling it is called directly bymaketx call
; and so usages should likely simply converge onAssertOriginCall
.AssertOriginCall
provides a good pattern to ensure functions are only called directly by end-users.std.IsOriginCall
should likely be replaced bystd.PrevRealm().IsUser()
, as PrevRealm ignores frames within the same realm.NOTE: a previous version considered also the removal of
GetOriginCall
, in light of discussions (see-also this comment) we're not removing it for now.Status: consensus.
References:
GetOrigCaller()
withPrevRealm.Addr()
#1577IsOriginCall
/AssertOriginCall
rely onPrevRealm
#1048std.TestXYZ
functions #1521Adding
crypto/bech32
and using it in place of a native
DerivePkgAddr
.Why: allows to use pure Gno implementations for
DerivePkgAddr
, removing the number of natively-defined function. Allows other realms to use and play withbech32
functions as necessary.other ideas:
Status: consensus (w/out jae).
Work started in #2425, browse code.
Manipulate entire contexts instead of
TestSetX
functionsConsequently, removing most (all?)
Test-
functions.See example
testing.Context
in #2425To be used either with a
Run(closure func())
method which executes the function in the given context; OR with atesting.SetContext
function now that test functions are executed in separete contexts (#2975).Why: allows to have a single context, accessible programmatically, to modify the entire testing context and allow constructing other helper functions on top, with behaviours defined in Gno. (Think a
SkipHeight
which modifies both the height and the timestamp, rather than having this defined in aTestSkipHeights
native function).Status: consensus (w/out jae).
References:
std.TestXYZ
functions #1521gno test
#2338Realm-scoped Deposits instead of OrigSend
Why: we will likely want a mechanism for a realm to send coins to another and access functions/methods guarded by OrigSend; similarly to the move we've done from
GetOrigCall
toPrevRealm().Addr()
. For this reason, a rename toDeposits
is hypothesized, which is reset by default when a realm calls another realm (exact mechanism for how a Deposit is set TBD). Similarly, the "Banker changes" below propose to change theOrigSend
banker to anAllowance
banker, to reflect the shift toDeposit
or similar mechanism.Status: pending discussion.
Note: need, even for the end-user, to prevent cases of MsgRun being able to abuse a OrigSend-guarded function, by calling it repeatedly (ie. the
Deposit
should possibly change if calling the realm again, at another time.)ImportPath instead of PkgPath
Why:
PkgPath
, aside from containing an abbreviation, can be ambiguous (as it refers to the path used by both pure packages and realms), and Go seems to more generally adopt the name "import path".Status: pending discussions.
References:
std
package API more user-friendly #1576Banker changes
This is mostly a refactoring of the API, partly also related to the GRC20 refactor. In summary:
BankerType
, create different constructors for different banker types.OrigSendBanker
, removing the need also for aOrigSendSpent
, making the API similar to that of grc20 withNewAllowanceBanker
.Balance
instead ofGetCoins
Supply
instead ofTotalCoin
Send
instead ofSendCoin
Issue
instead ofIssueCoin
. (consider:Mint
)Burn
instead ofRemoveCoin
.Issue
andBurn
- see: Expect full denoms in Banker.IssueCoin and Banker.RemoveCoin #2107chain.Realm.Denom
to construct denominations from package paths.Why: using constructor allows us to have specific constructors, like for
NewAllowanceBanker
. Renaming of the methods is done mostly to avoid the redundantCoin
. Using full denominations allows the same denom string to be used consistently in all banker methods, rather than having the shorter one forIssue
andBurn
.Status: pending discussions.
References:
Removing CallerAt, GetOrigPkgAddr, RawAddress
CallerAt
seems to be outdated in the current landscape withPrevRealm
.GetOrigPkgAddr
seems to be outdated with mechanism likeAssertOriginCall
andPrevRealm
.RawAddress
seems pointless with acrypto/bech32
package capable of breaking down the bits of the address.Why: working from a smaller API with only what's proven necessary in real-life usage will allow us to ship a more "conservative" mainnet standard library; and adding new things once we verify a need for them.
Status: pending discussions.
References:
std
#1475 (comment)Something other than
Realm
forCurrent/PrevRealm
With #667, we agreed to consider end-users as "realms" of their own, considering both end-users and "package" realms to be realms alike; justifying the return of
PrevRealm()
.We should revisit this, as
CurrentRealm
/PrevRealm
is the only circumstance where we say a realm is ambiguously a end-user or a package with state; in most other usages verbally, on GitHub and in our documentation, a "realm" is simply a package with state.Status: pending discussions.
References:
The text was updated successfully, but these errors were encountered: