-
Notifications
You must be signed in to change notification settings - Fork 1k
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: PrimitiveValueType and Generic Pointers #492
Comments
@Ultrahead The proposal I linked is dealing with not an attribute but a keyword that can be enforced at compile time and across assemblies. |
related #144 |
If the blittable proposal was selected as Champion, and if it will also allow the use of generic pointers of blittable structs, then this proposal should be closed. Please consider adding a new getter to the Type and ValueType classes: IsBlittable. |
#187 is part of C# 7.3. |
@Ultrahead commented on Thu Apr 23 2015
The idea here is to create a new type, say, "PrimitiveValueType" that would inherit directly from ValueType, and would not allow declaring reference-type field members, only value-type fields’ members that do not hold reference-types. For example:
This would also open the door another proposed feature: Generic Pointers. Take for instance the following operation:
By redefining types like int, single, double, bool, and so on so forth, so that they become specifications of PrimitiveValueType, fixed-type buferring could be enhanced so that any type defined as primitive is supported. Example:
For reference, this proposal is related to this discussion on codeplex: http://roslyn.codeplex.com/discussions/543883
@VSadov commented on Thu Apr 23 2015
This seems somewhat similar (if not a duplicate) to the unmanaged generic type constraints. #126
@stephentoub
@zahirtezcan commented on Fri Apr 24 2015
This seems really good for interop purposes. Since primitive types can only contain other primitive types, fixed buffers or pointers: We can use sizeof operator on primitive types, such that size may be known in compile time. For this purpose there should be a way to tell the compiler about packing etc.
If that becomes possible, generic context we will be able to say
@HaloFour commented on Fri Apr 24 2015
@zahirtezcan Currently you can use
StructLayoutAttribute
to inform the compiler about the packing (and actual size) of a structure. The runtime defaults to aligning based on the size of the largest element in the structure otherwise.@zahirtezcan commented on Fri Apr 24 2015
@HaloFour Attributes are for the run-time to determine the size and layout of the structure though. But if compiler can detect size and layout statically; we can use sizeof on primitive structures and that will be whole new level for pointer/interop/memory operations
@HaloFour commented on Fri Apr 24 2015
@zahirtezcan Actually the
StructLayoutAttribute
never survives to the compiled binary. It exists as a "pseudo-attribute" to give the C# compiler a syntax for specifying the layout and characteristics of the struct without having to define a new syntax. The compiler is, of course, free to calculate that on its own and specify that metadata. It would have to in these cases since the size of the struct would have to be known for fixed sized buffers to be supported since the C# compiler has to account for the total size of the buffer.@dsaf commented on Mon Apr 27 2015
Could it be used for implementing units of measure? #144
@MikePopoloski commented on Tue Apr 28 2015
+1
Lack of generic pointers is one of my biggest pain points with C#.
@VSadov commented on Tue Apr 28 2015
@MikePopoloski - about generic pointers. I am curious about particular scenarios.
Is that specifically about
-- pointers - as in generalizing byte* to primitive_struct* and use that in unsafe/pinned context,
or about
-- inner references - as in getting a managed reference to an element of T[] and pass that around like described in #118?
@Ultrahead commented on Tue Apr 28 2015
@VSadov: I was migrating the proposal I had submitted to codeplex. Now, for what I can read through #126 and #118, my proposal is not a duplicate since I meant the last two features proposed in my first post here -that is generic pointers and fixed-type buferring- for unsafe contexts.
@zahirtezcan: exactly!
@dsaf: I don't see why not. It would nice to have user-defined literals as in C++11, so you can do something like:
So when you use it like
var myRadian = 45_rad;
orvar myRadian = 45.23f_rad;
, the literal will pick the corresponding implicit operator to get the Radian;@MikePopoloski: thanks!
@MikePopoloski commented on Tue Apr 28 2015
@VSadov More of the former than the latter. Things like reading binary files from disk, writing binary blobs to the network, or manipulating native memory blocks allocated for maximum control of cache layout (for example, particle systems). I usually end up using an IL-rewriting process to let me read and write generic pointers from/into a native memory block, since the CLR supports it just fine.
If that, and the calli instruction were exposed to C# code it'd make me super happy. I'd no longer need to run the cumbersome IL rewriting build step.
@Ultrahead commented on Tue Apr 28 2015
@MikePopoloski: "Things like ..." +1 on that
@dsaf commented on Wed Apr 29 2015
Would it lift the unpleasant constants limitation?
https://msdn.microsoft.com/en-us/library/e6w8fe1b.aspx
I want to be able to pass e.g. a DateTime or a TimeSpan or a Vector2 to a custom attribute, but there is no way to do this at the moment.
Should it be a separate issue or the current one covers it?
@Ultrahead commented on Wed Apr 29 2015
Interesting question, @dsaf .
To be honest, I believe it goes beyond the scope of my suggestion since it would most likely requiere a deeper change in the compiler than adding a "primitive" type.
The thing is that only "simple" built-in types (plus strings) can be declared as constants, leaving out, for this case, user-defined primitives which are initialized at runtime. In order to remove such restriction the compiler should be capable of detecting beforehand which primitives can be deemed as "simple" types, and therefore, that can be assigned at compile time.
And that is a requirement that imvho should be part of a separate issue.
@dsaf commented on Wed Apr 29 2015
I was thinking that this:
Would lead to this:
It's interesting that custom attribute constructors accepting non-primitive parameters are allowed to be declared but not to be used :)
@Ultrahead commented on Wed Apr 29 2015
At first, for a moment, I thought the same as you have, but then I realized that there would be more in a type to be considered simple by the compiler than be redefined as a primitive, or otherwise, structs like DateTime, TimeSpan and Vector2 would already be allowed to be declared as constants in the current version of .NET.
@Ultrahead commented on Wed Apr 29 2015
And of course, if I'm wrong, then that would be a welcome feature to have as a result of the proposed primitive type (that is, without the need of submitting a separate issue).
@HaloFour commented on Wed Apr 29 2015
@dsaf
I believe that such changes would require modifications to the CLR, particularly where those constants are to be used with attributes. The limitations on what kinds of values can be encoded and deserialized for attributes are set by the runtime and are a relatively short list of very easy to serialize values, namely integral types,
char
,enum
,bool
,string
,Type
(by way of the full name encoded asstring
) or arrays of any of those types.For the most part it seems that this
primitive
type proposal is compiler candy, a way to explicitly specify that a standardstruct
is to contain only other value types of a size known at compile-time. That would allow for fixed-size buffers using the compiler trickery currently used. Although the concept of "generic pointers" is an entirely different ballgame.@Ultrahead commented on Wed Apr 29 2015
Indeed, but having a primitive type in the language would ease such task if used as a required constraint (that is, not allowing type declared as structs for generic pointers even if they hold no reference types within). So, the only way to have generic pointers would be by the use of primitives.
@Ultrahead commented on Thu Oct 08 2015
This branch could really help to bring PrimitiveValueType base class to life: http://xoofx.com/blog/2015/09/27/struct-inheritance-in-csharp-with-roslyn-and-coreclr/
@HaloFour commented on Thu Oct 08 2015
@Ultrahead I don't see how that branch does anything to make this proposal possible. You still have the problem that dereferencing that pointer requires that the compiler know at compile time the exact offset in bytes of every member or element. The compiler can't know that with generic methods.
As for the branch itself, calling that "struct inheritance" seems like a bit of a stretch. A form of struct composition maybe. The behavior would probably not be what people would expect, especially the slicing for upcasting which makes downcasting impossible.
@gafter commented on Thu Oct 08 2015
@Ultrahead @HaloFour Actually, I like the idea of struct inheritance. The problem we run into is the meaning of interface implementations. You should be able to override the implementation of a method provided by the base struct, but that is incompatible with the tearing you get when you cast to the base struct.
@Ultrahead commented on Fri Oct 09 2015
@HaloFour: At compile time, the compiler will know the size of each type of primitive. So, couldn't that task be endorsed to the CLR so that it infers it at runtime, instead?
@xoofx commented on Fri Oct 09 2015
We definitely need a way to express/enforce blittable structs (so that if someone add a managed field, we can detect it) and enforce this at generic constraint level, to be able in the end for example, to take a pointer from it (and pass this pointer to a native method then).
As @MikePopoloski mentioned, we are currently workaround it by IL rewriting this, just get an access to this feature which is very annoying (In SharpDX for example, it is all around used, declared in this file, and IL rewrite here, and used for example here)
In the language, it could also be just a System attribute (Blittable), and on the constraint, we could specify constraints on attributes (
where MyType has Blittable(Attribute)
)@MikePopoloski commented on Sat Oct 10 2015
Also note that similar things can be done using typed references: link
Of course, this abuses the internal structure of a typed reference, but it does exactly what I want in a very efficient manner.
@xoofx commented on Sun Oct 11 2015
neat! didn't know that _makeref was also working with generics
@nietras commented on Thu Feb 04 2016
I guess my proposal here is a redundant form of this one Unmanaged generic type constraint + generic pointers Note that this proposal however does not require a new type specifier.
@jamesqo commented on Mon May 09 2016
Enthusiastically +1'ing this proposal, having generic pointers would be a very welcome addition to C# for me. A couple of things I'd do differently, though:
Make
primitive
a modifier for thestruct
keyword, so e.g. you would writeprimitive
is just a way for the compiler to verify that the type does not contain any reference fields, it doesn't get reflected at all in the emitted IL. This would mean we could work with existing types that don't have the modifier and use them with theprimitive
constraint:In other words, types that don't declare
primitive
might be primitive, types that do are always primitive. This means we don't have to change existing code.No
PrimitiveValueType
base class, since that would probably break things like reflection if you tried to do thisThe text was updated successfully, but these errors were encountered: