Open Nukepayload2 opened 6 years ago
They have confirmed that this behavior is by design. I don't understand why they are not intend to let stack-only structures consumable in VB when c# is able to define them. Maybe they thought ref structs are similar to unsafe types. So, in most cases, VB developers may not hurry to consume these types. But this assumption does not make sense, because ref structs are not unsafe codes. They can be defined or be used in C# 7.2 outside of the unsafe
context, why can't we just consume them in VB?
Both System.Span(Of T)
and System.ReadOnlySpan(Of T)
are important new APIs for .NET developers who care about both performance and type safety. We should feel natural when using them, rather than seeing the annoying BC30668 compilation error.
Just throwing out a possible syntax.
Sub M(ReadOnly ByRef parameter As T)
Dim x As Readonly ByRef T = arg
End Sub
The first Readonly
is new Parameter modifier.
The second ReadOnly
and ByRef
as extending the type signature, akin to nullables.
This code won't cause error:
Module Program
Sub Main(args As String())
Dim arr As Integer() = {1, 2, 3, 4, 5}
Dim span = arr.AsSpan()
Console.WriteLine(span(1))
End Sub
End Module
It seems that the compiler only doesn't ignore the ObsoleteAttribute
.
@Berrysoft the VB compiler should verify that all ref struct
s are not stored on the heap, rather than simply ignore the ObsoleteAttribute
. The following code should produce compile-time error, but the current behavior is compilation succeed without any warning.
' Depends on nuget package "System.Memory 4.5.0"
Module Program
Dim span1 As Object
Sub Main(args As String())
Dim arr = New Byte() {1, 2, 3, 4, 5}
span1 = arr.AsSpan ' No compilation error here. The expected error code is BC31394.
Console.WriteLine("Hello World!")
End Sub
End Module
@Nukepayload2 Surely it should, though your code will cause a runtime exception: System.InvalidProgramException:“Cannot create boxed ByRef-like values.”
It may be thrown by JIT.
And I find that this code will cause InvalidProgramException
too:
Module Program
Sub Main(args As String())
Dim rls As RefLikeStruct
Console.WriteLine(rls.ToString())
End Sub
End Module
<System.Runtime.CompilerServices.IsByRefLike()>
Structure RefLikeStruct
Public A As Integer
End Structure
Seems that RefLikeStruct
is a real stack-only type!
Aside from the bugs recorded in https://github.com/dotnet/roslyn/issues/28558, this is by design. We'll take this as a feature request to support the use of ref structs in VB.
2.5 years!
@gafter
This issue threatens a bottleneck in VB.NET going forward, as more uses of ref structs are introduced into .NET 5 as it matures. I'm adding my voice to the feature request.
I'd also like to add my support for byref like types in VB.NET @gafter. The whole point of byref like types is that they are a safe way to achieve something similar to pointers. Also, I'm aware that VB.NET isn't getting new features anymore, but I think it is reasonable to expect VB.NET to be usable with modern .NET and C# features, currently it is really difficult to do a lot of things and it's just a shame and so unnecessary honestly.
With .NET 7's byref fields, a lot of libraries will be making custom byref structs, many of which that will be public, which VB.NET will be able to use absolutely no api containing. This is exactly what happened with the unmanaged
constraint, e.g. with ImageSharp
, because it uses that constraint internally, suddenly almost none of the library can work in VB.NET anymore.
If VB.NET absolutely must not be able to write unsafe code, it should still be able to consume code that happens to be unsafe that's written in other languages as it always has been able to do (obviously other than constructors which take pointers), so it should be able to use spans since they're safe by design, and the unmanaged
constraint so it can consume C# code even if it doesn't allow you to do anything additional in VB.NET.
That's my opinion anyway.
I agree that we need support for ref struct
in Visual Basic .NET. I completely understand Microsoft's strategy to not develop Visual Basic .NET any further, but this is essentially making Visual Basic .NET development in .NET 7 (in .NET 6 there are workarounds) impossible. I just tried to upgrade an application we maintained in .NET 6 in Visual Basic .NET and I get hundreds of errors regarding ref struct
not being supported by the compiler.
@BerndPodhradsky can you give some examples of ref struct
instances you're trying to use? I understand ref structs
being on the periphery but are they really a part of the common workflows. I know some of the JsonReader stuff is using them but there are non ref struct alternatives, right?
@AnthonyDGreen I use RSA.ImportPkcs8PrivateKey
to create JWTs and if you look at the documentation (https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importpkcs8privatekey?view=net-7.0) you can see that there's only one overload that requires a ReadOnlySpan
. However, I cannot call AsSpan
on an IEnumerable
in .NET 7, because I immediately get error messages indicating that the Visual Basic .NET compiler does not support it.
I see. That is pretty silly.
@AnthonyDGreen Funnily enough, in .NET 6 I was able to call that function overload by calling the AsSpan
extension method for IEnumerable
s - do you have any idea why that isn't allowed any longer in .NET 7?
I'd like to add that I find it increasingly difficult to do anything in VB.NET these days particularly due to lack of byref-like structures support (I don't have specific examples on the top of my head), and am gradually moving code to C# as a result of this because there is lots of code I simply cannot write (it's a pain to have to move large amounts of existing code). It would be really, really good if VB.NET would support ref struct
s natively (at least for consumption).
I doubt VB.NET is in mind for many of the new .NET APIs, and therefore the situation will only get worse as there are likely to be many APIs that cannot be accessed on VB.NET due to lack of ref struct
s (and a similar situation for unmanaged
for low-level libraries like image manipulation libraries e.g. ImageSharp
).
Also, I've seen a lot of people saying the reason they shouldn't be supported is because they're 'unsafe', but the whole point of ref structs is that they're designed to be safe.
@hamarb123 To be honest I never really understood that argument in the first place; if stuff shouldn't be used because it's unsafe, by should/can it be used in C#? I fear we will have to move our code base to C# as well but IMHO code editor support for C# is in some cases worse than for Visual Basic .NET and it's a pain once you're used to VB (e.g. indented region content etc.).
I use C# mostly these days, but the only reason I started using it was because I determined that MS doesn't want things to be possible in VB.NET (e.g. unsafe etc), so I started using C#, but I still have many large projects in VB, and VB not supporting many features makes it even more difficult to move the code into C# (because I have to write C# that will work with VB because the rest is still in VB, which also inevitably reduces performance compared to if I could just write the C# I want to write).
@BerndPodhradsky
Try mark the method that uses ref structs in VB with the <Obsolete>
attr. If they closed this back door as they intended while ago, then you can just change VB compiler version in you project file to 16.9. I think this will make this workaround work.
@VBAndCs Unfortunately neither <Obsolete>
nor changing the language version fixed the issue.
Haden't heard of ModVB before, is it open source? Can you have ModVB and VB.NET working side-by-side?
@hamarb123 It is a pre-release version. You can setup it as a VS extension, open a VB.NET project, then add a NuGet to make the project use ModVB instead VB.NET. All instruction in this post
@BerndPodhradsky Create a dll that targets .NET 6.0, and add to it all code that uses the ref structs, then use it in you .NET 7 apps.
If I use stack only type in my VB code, error BC30668 will block compilation. I'm using VS2017 15.6.7.
Steps to reproduce:
<LangVersion>Latest</LangVersion>
in<PropertyGroup>
.public ref struct StackOnlyType {}
in that .cs file.Dim errorType As StackOnlyType
toSub Main
.Expected behavior:
The code should compile, because I'm not trying to put a stack-only variable on the heap.
Actual behavior:
Error: BC30668 "Types with embedded references are not supported in this version of your compiler"