-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: Go 2: add untyped() type conversion for integer constants #31076
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
Comments
Thanks. This leads to the obvious question of how to handle float, complex, rune, string, and bool constants. These constants too can be both untyped and have a type. Should |
You can't normally call a function in a constant instantiation, for obvious reasons. Apparently the The problem you're trying to address seems to stem from the fact that they're returning typed constants. Maybe it would make more sense for them to return untyped constants directly, rather than adding a new pseudo-conversion that would only probably really be used in conjunction with them. Alternatively, make this an |
[responding to Ian] The notion of [responding to DeedleFake]
const h = "hello"
const l = len(h)
const example = byte(5) + l
# xor
./xor.go:26:25: invalid operation: byte(5) + l (mismatched types byte and int) ...and here's an example. the length of "hello" is not the number 5, but rather Go's My thought was just to leave everything as is and offer untyped() as a rescue means for people like me who want their 5 to be a 5 and their log2ByteSize to be a 3. On reflection, maybe this was aiming too low. Maybe it is const type assignment that should be made even more just in time for Go2. I am now sitting here thinking what the implication of this rule would be: never assign a type to a const expression unless absolutely unavoidable and then unassign that type as soon as is possible. Some examples:
evaluated as a zero of no type, "0" This is great for me, but is complicated if the developer then tries
because this has potentially confusing meanings. (not confusing mathematically, just that masking a high-one and inverting would not turn that leading zero into a one as may be expected if they are thinking the constant has 16-bittedness as an attribute. Alternatives that work are: const pdp1140mem uint16 = ^uint16(0)
const pdp1140mask = ^pdp1140mem or const pdp1140mem = uint16(^uint16(0))
const pdp1140mask = ^pdp1140mem or const pdp1140mem = ^uint16(0)
const pdp1140mask = ^uint16(pdp1140mem) These all make sense, but highlight the breaking changes that newly understood ultra late type binding and rapid unbinding would bring. In their defense, they could be automagically rewritten by the gofix tooling. About pure functionsNot only the |
Here's a nice motivating example for pure functions, from runtime/stack.go:
A pure round-up-to-power-of-two function would be nice instead. |
Alas the round-up-to-power-of-two function does require an if test for "am i already a power of two" or else what you have here. With the if passed to prove not 2^n, then it can be a simple shift by leading zeroes. Without C's ternary operator or the Algol like a := if b then c else d fi, you must have the code you show (with the missing ">> 32" last step for generality). We could add this to bits, and then with pure function support it would be there for you. func RoundUpPowerTwo(n uint64) uint64{
// special cases
switch {
case n=0:
return 1
case (n&(n-1)) == 0: // already a power of two
return n
}
// general case: next higher power of two
return 1<<bits.LeadingZeros64(n)
} |
I'm very much sympathetic to this idea - it would indeed be nice to have an "untype" mechanism. I also agree that most of these problems would disappear if some of the built-in functions such as There may still be a need to explicitly remove a type for which we might want to have an Regarding your specific example at the top, computing Finally, we actually do have a mechanism in the language to remove type information from numeric values ! :-) That operation is (left or right) shift. Shifts are the only operation that take two operands of different types to produce a result of one of those types (the type of the left operand). If the left operand is untyped, then the result remains untyped no matter the type of the right operand. This can be used to assemble any integer from untyped bits. Here's an example: package main
import "fmt"
const (
// typed x
x byte = 0x5b // 0b_0101_1011
// untyped bits of x
b0 = 1 - 1>>(x>>0&1)
b1 = 1 - 1>>(x>>1&1)
b2 = 1 - 1>>(x>>2&1)
b3 = 1 - 1>>(x>>3&1)
b4 = 1 - 1>>(x>>4&1)
b5 = 1 - 1>>(x>>5&1)
b6 = 1 - 1>>(x>>6&1)
b7 = 1 - 1>>(x>>7&1)
// create an untyped u from the untyped bits of x
u = b0<<0 | b1<<1 | b2<<2 | b3<<3 | b4<<4 | b5<<5 | b6<<6 | b7<<7
// verify that u is untyped
// (if it were typed we couldn't assign it to a complex128)
_ complex128 = u
)
func main() {
fmt.Println(b7, b6, b5, b4, b3, b2, b1, b0)
fmt.Printf("%08b == %08b (%v)\n", x, u, x == u)
} The scheme can be applied to any integer built-in type which can be "sampled" via the use of shifts; its source code size is O(n) where n is the number of bits of the original value... - fun, fun, fun! |
I added #31795. |
PS: If |
@MichaelTJones Do you think that @griesemer 's alternate proposal #31795 would address the use cases of an |
ping @MichaelTJones |
Closing, as @MichaelTJones replied at #31795 (comment) that #31795 would be work instead. |
I'm fine with closing this, but for the record, @MichaelTJones reply came before I mentioned that we couldn't do #31795 in a backward-compatible way for the |
Much Griesmer-shifting is in my future, but it will work. That's really the
question--is there a workable solution? Yes there is, so ok.
…On Wed, May 29, 2019 at 9:59 AM Robert Griesemer ***@***.***> wrote:
I'm fine with closing this, but for the record, @MichaelTJones
<https://github.com/MichaelTJones> reply came before I mentioned that we
couldn't do #31795 <#31795> in a
backward-compatible way for the unsafe.Sizeof/Alignof/Offsetof functions
because they return a uintptr. (I suspect one of the common use cases is
wanting to have the size of a type as an untyped value, which would require
unsafe.Sizeof.) But we could provide a trivial gofix (or even gofmt).
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#31076?email_source=notifications&email_token=AB4DFJI4Z6AZVCNNHIN4D2DPX2Y7RA5CNFSM4HBW24TKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWP7DEA#issuecomment-497021328>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AB4DFJKVWDQSFMR4R5WX4RTPX2Y7RANCNFSM4HBW24TA>
.
--
*Michael T. [email protected] <[email protected]>*
|
Turns out #31795 was closed. @MichaelTJones, do you want this re-opened? |
Nope. It is not a problem for others and workarounds have been shared.
…On Tue, Dec 3, 2019 at 2:52 PM Brad Fitzpatrick ***@***.***> wrote:
Turns out #31795 <#31795> was closed.
@MichaelTJones <https://github.com/MichaelTJones>, do you want this
re-opened?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#31076?email_source=notifications&email_token=AB4DFJINQF4GFH6AVVJE5UTQW3PL5A5CNFSM4HBW24TKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEF3DBKI#issuecomment-561393833>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB4DFJPSWQCYUVYLDFP42QLQW3PL5ANCNFSM4HBW24TA>
.
--
*Michael T. [email protected] <[email protected]>*
|
Proposal
This proposal extends the late-type-binding aspect of untyped constants to situations where the construction of a constant caused a type to be set, but the result is best used/considered as an untyped constant.
Background
There is a gentle robustness to untyped constants. I can add a plain "3" to any numeric expression without casts and verbosity. I want that for derived constants as well and offer the rationalization that even where typed constants are important in a computation, as in
^uint16(0)
, the result may not itself be usefully typed—the 65535 that results is just the integer 65535, so why should I not be able to add it to an int or uint loop index?untyped(expr)
solves this.Example
Here is an example from a few days ago using the present state:
Neither the int in
int(unsafe.Sizeof(uintptr(0)))
nor the uintptr inuintptr(wordBytes - 1)
were what I wanted; I wanted a plain untyped integer. (As Rob asked in a video, "What was wrong with the old integer 80?") It was just that the expressions garnered a type and I could not "un-type" them.I would like to see this instead:
...which would have given me 8, 3, and 7 as simple constants for further convenient use.
Compatibility
This does introduce a new symbol so it is not impossible that it would be seen as violating the Go1 promise.
Jan Mercl pointed out that users can create a type of their own named
untyped()
as shown here in the Go Playground, so that makes it a guarantee breaking change.Ian lance Taylor commented that it may be seen in as non-breaking under the notion that "If we treat untyped as an ordinary predeclared identifier, then I think the proposal remains backward compatible. The new predeclared untyped is not available in packages that defined the name untyped in package scope. And there is no other way write untyped(EXPR)."
In any case it is a localized change in that it is no change unless a user's created a type named "untyped" and if they have, the compiler and go vet (and go fix) will know and can respond as appropriate, one version of which is to use the user's type cast and then therefore it is not a change in the contract sense but admittedly becomes a potential source of confusion in that hypothetical case.
Ambiguities
This proposal originally focused on integer constants. But discussion here has made clear that it is just as useful generally so that utility and the appeal of orthogonality say that untyped() could remove the
float128
from a complex constant just as beneficially.Implementation
Simple change in the semantic actions of the parser to drop whatever type has been set on a constant.
The text was updated successfully, but these errors were encountered: