-
Notifications
You must be signed in to change notification settings - Fork 842
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
Why the usage of int
to hold values that overflow it (when it can only 32 bits wide)
#24
Comments
int
to hold values that overflow it (when it's only 32 bits wide)int
to hold values that overflow it (when it can only 32 bits wide)
Hi @bbuck Thanks for sharing your time to take a look into this project, appreciate it a lot! 👍🏻 I contributed part of that chunk of code that was ported from graphql-js. At that point of time, I found it strange that integer value was restricted that way and wondered whether we should just support int64 since golang does not the same limitations as Javascript. But looking deeper into it, I found out that the GraphQL specs specify support only for signed 32-bit integers. But to add to the confusion, it seems that graphql-js implementation supports 52-bits integer. There have been discussions in the graphql-js camp about 64-bit support and the direction for graphql-js whether to update the spec or implementation regarding this 52-bits inconsistency. At this moment, it seems that a part of the GraphQL community is voting for a strict specs of signed 32-bits integer on all platforms, both client and server. (I encourage everyone else to make your voice be heard as well). Personally, I would love to adopt support for 64-bit since golang provides it for free (yay!) but we also have to consider GraphQL clients that consume the results won't necessarily support 64-bit. So it makes sense to support the lowest common denominator. What do you guys think? /cc @chris-ramon |
I guess what I was more getting it is that internally I feel that Mostly because the application itself might not use int, like in my use case where gorm defaults it's ID field to The best comparison I have is that, during this session of this one particular course here (which may or may not be accessible to you, I hope so) they discuss returning a JavaScript object when graphql-js was told to expect a GraphQLString so the final result returned is tl;dr Internally I think graphql-go should handle "maximum" values (so to speak) and just convert them to the final result that GraphQL has standardized. Also, you're welcome. I've just started (like less than a week ago) diving into GraphQL and I'm super excited about it and want something to do in Go so I hope to try and start contributing some useful things going forward. |
Ah, I see what you mean right now lol 👍🏻 Yeah you are right, those
Specifying them as
Thanks for that catch 😉 I see you already have a PR open; you think you want to include these changes in them as well? And I believe those Again, appreciate your contribution and looking forward for more! |
I think both great points. I'll throw that in the PR!
|
@sogko So I guess I have a dilemma here. Should we be returning |
Hey @bbuck I think for integer values (int, int32, int64, uint, et al) should return the same type as its input when passed into
This is what I imagine the implementation it could be. // intOrNil checks if value is within allowed range.
// Returns the original value if ok, else nil.
func intOrNil(value interface{}) interface{} {
val := int64(value)
if val <= MaxInt && val >= MinInt {
return value
}
return nil
}
// For non-integers (strings, bool, floats), coerce to `int`
// For integers (including its variations), value should be within
// signed 52-bit range for its original input type. Else returns nil
// TODO: The below code can be written more elegantly I guess lol
func coerceInt(value interface{}) interface{} {
switch value := value.(type) {
case bool:
if value == true {
return int(1)
}
return int(0)
case int:
return intOrNil(value) // returns as int or nil
case int32:
return intOrNil(value) // returns as int32 or nil
case int64:
return intOrNil(value) // returns as int64 or nil
case uint:
// TODO: check if uint value is larger than signed int64
return intOrNil(value) // returns as uint or nil
// TODO: case uint8, uint16 etc..
case float32:
if intOrNil(value) == nil {
return nil
}
return int(value) // casts float32 as int
case float64:
return intOrNil(value) // returns as int64 or nil
case string:
val, err := strconv.ParseFloat(value, 0)
if err != nil {
return nil
}
return coerceInt(val)
}
return int(0)
} What do you think about this? |
Okay I've updated my pull request with some of the ideas you posted. I modified the switch piece so that it returns the "best choice" of I've updated the tests so that corresponding types are validated. Personally, I'm not sure how comfortable I feel with that varied return values. I think I would be more comfortable if only |
After pushing and commenting I suppose there is little reason specifically with forcing |
Just to keep this issue up-to-date: I think this issue is still valid, and now that most of the codebase has settle down a little bit from the API changes, we can re-look into this. |
Just to not here as well that #83 is an updated proposed fix. Also fixes the invalid bit size (according to spec) numbers used which was also updated in the graphql-js library. |
This should be closed now. |
In the scalars.go file the
coerceInt
function andintOrNil
deal with checking against large integer values but they use theint
type:The constants you have for
MaxInt
andMinInt
will only work fine when this is running on a 64-bit machine. I think it would be much safer to useint64
explicitly here since that appears to be what you really want and you can eliminate the 32 vs. 64 issues completely. This isn't something I've directly run across, but it just feels wrong to depend on the variable sizeint
type when you're using values that fit only inside of anint64
.The text was updated successfully, but these errors were encountered: