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: unsafe: add Data for arbitrary type casts #64843
Comments
Have you considered writing this once: func As[T, F any](from F) T {
return *(*T)(unsafe.Pointer(&from))
} And then using the "clean" Also I think it is good if How the implementation would look like ? type S struct{
x uint
a, b, c unsafe.Data
y uint
} How is the compiler supposed to know how to layout I could see the compiler always rewriting this to |
What kind of type is unsafe.Data? It's not a pointer; it's a (C++-like) reference to the variable pointed to by an unsafe.Pointer, which has unknown size and other characteristics. Adding a new fundamental data type (which means a new reflect.Kind, breaking all existing reflect.Type switches) would be a major language change just to eliminate a tiny amount of conversion in code that is doing something unsafe. That's clearly the wrong choice. If you're using unsafe, the conversion is the least of your worries. Follow @Jorropo's suggestion and write a simple helper function. |
One way to think of This Reading through the proposed solution to infer the underlying problem, it seems like the main thing you want is the ability to interpret an arbitrary block of memory as if it were some specific type. Rust has such an operation, which it calls "transmute". It is designed as a generic function which takes a value of any type (but the type must be known) and reinterprets its memory representation as some other specified type. The Do you think that including something with the same API and implementation as your Without special compiler support I don't think it would be possible to enforce that both types are the same size at compile time, but since we're in
If any of the above do not hold, the result is undefined. |
"As" was just example of operation which we need sometimes. I'm not good in rust, but it's transmute seems like solution for problems i'm raising hare. There are many cases where this operation may simplify our code, as example i worked on project (it was't soluction created by me) where some data was stored in byte slice and X begining bytes was used for meta information of different types. There were integers of different size and sometimes structures. Something like that: x := make([]byte, 8) but much more uglier because there was not unsafe.Slice Data in stdlib when i face it |
@gohryt imo this is bad code and you should write But that aside, I don't understand how x := int64(uintptr(unsafe.Pointer(unsafe.SliceData(x))))
Can you give an other example of operation where |
Is the proposal here to invent a way to treat the fields of a structure as if you knew how they were laid out in memory? This proposed change would affect all the developers who were deprived of the benefit of this optimization, and required (in many cases) to do by hand an optimization that a computer could do better and faster. |
There is a non-insignificant amount of unsafe Go code that relies on the current field order and padding. I'm also curious how explicit "explicitly requested" is. Currently, we might use cgo in one package, but pass struct types from another package to cgo. |
If unsafe.Data is a type, what does 'var x unsafe.Data' mean? |
This proposal has been added to the active column of the proposals project |
If we really need it as castable type it may be like array of size in bytes. |
It seems to me that the proposed unsafe.Data is an unsafe.Pointer with a type conversion syntax sugar. |
It seems that the purpose of unsafe.Data is to reduce the number of characters typed in type conversions compared to unsafe.Pointer. var x unsafe.Data it's a few fewer characters than writing "var x unsafe.Pointer" in convert type. For example in #64843 (comment) |
@qiulaidongfeng /models/user.go
/entities/user.go
in your work? |
@gohryt In that case you could write, in package
or perhaps
|
You don't need an unsafe cast to convert one to the other: https://go.dev/play/p/npTCvR8_kcE |
@gohryt even if you really want to use func Transmute[T, F any](from F) T {
return *(*T)(unsafe.Pointer(&from))
}
// ...
u := Transmute[entities.User, models.User](u) |
Based on the discussion above, this proposal seems like a likely decline. |
No change in consensus, so declined. |
Proposal Details
Author
Consider myself as intermediate go developer.
Experience: 3 years in production with go.
Other language experience: the most experience is in Js, tried many interesting things from LLVM IR to Nim and Odin.
Related proposals
Has this been proposed before? No.
Affect error handling: no.
Would this change make Go easier or harder to learn, and why?
This will not affect most of go developers. This will not be mandatory-to-use.
Proposal
Add a new virtual type "Data" to unsafe package. Currently we have .Pointer and the real world example of it's usage is:
it's solution which we have now, not best solution. Proposed .Data type should work as in example below:
This solution will make our code cleaner, more understandable for normal go devs and will allow some conversions like as in case when we have two equal structures with different print (json, yaml) tags.
This may be too permissive for golang code so i think we should restrict it with size check - conversion should be succesful only if both's .Sizeof is equal.
Backward compatibility:
Full because of no "Data" keyword in package unsafe.
Cost of this proposal:
Tools to rework: compiler
Compile time cost: no cost
Runtime cost: no cost
Possible implementation:
Just as .Pointer
The text was updated successfully, but these errors were encountered: