[Proposal] Add the `Trait` keyword and other new features to VB.NET... or shall we?
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 328
- Forks
- 71
- PR merge metrics
- No merged PRs in 30d
Description
By now, C# supports generic math through static abstract members in interfaces, and I've recently heard that something like static interface is on its way to C# as well. I'm comfortable writing both C# and VB.NET, but watching the following function in my VB.NET module refuse to compile is an out-and-out nightmare for me:
Imports System.Numerics
Public Module MyMathUtils
' Linearly interpolates between `left` and `right` by the given coefficient.
'
' NOTE: This relies on generic math (static abstract interface members). It compiles in C# today,
' but the current VB.NET compiler rejects it - which is exactly the gap this proposal targets.
Public Function Lerp(Of T As INumber(Of T))(left As T, right As T, coeff As T) As T
' BC32098: Type parameters cannot be used as qualifiers
If T.Compare(left, right) >= 0 Then
Throw New ArgumentException("left must be strictly less than right")
Else
' BC30452: Operator '-' is not defined for types 'T' and 'T'
Return left + (right - left) * coeff
End If
End Function
End Module
' If only VB.NET had a "shared interface" (static abstract members) like this...
Public Trait INumber(Of T As INumber(Of T))
Shared Operator +(left As T, right As T) As T
Shared Operator -(left As T, right As T) As T
Shared Operator *(left As T, right As T) As T
Shared Operator /(left As T, right As T) As T
' Negative if left < right, zero if equal, positive if left > right.
Shared Function Compare(left As T, right As T) As Integer
End Trait
' NOTE: The above sketches what a VB-native declaration mirroring `System.Numerics.INumber(Of T)`
' could look like, where the operators and the comparison are declared Shared (static) on the trait
' itself, so a type parameter constrained to it can invoke them directly such as `T.Compare(...)`
I've already come to terms with the fact that VB.NET is close to maintenance mode and lacks quite a few important features, with source-generated JSON parsing among them. That is exactly why @VbAndCs created the VB.NET Record Generator (RecGen) and published it on NuGet. In the same spirit, I've built two source generators of my own: TaggedUnionVB.Generator, which brings the upcoming C# 15 union syntax to VB.NET, and JsonContextGenerator.VisualBasic for source-generated JSON support.
The problem is that my JsonContextGenerator.VisualBasic breaks from time to time, throwing source-generator-related exceptions when I use it in my own VB.NET applications. My power to replenish the VB.NET ecosystem alone is limited, and I've had to tell myself to pause active development of my NuGet packages and GitHub side projects — I happen to be retaking the postgraduate entrance exam, which starts at the end of December. I'm writing this issue simply because I can't bear to watch VB.NET being treated like "the COBOL of .NET" by quite a few C# developers — and, if I'm honest, because I'm having a very hard time revising Politics and TCM-related subjects for my exam.
Meanwhile, I've even been daydreaming about Extender and Alias keywords that would follow in the footsteps of C#'s extension<T> syntax, as sketched below. Now I think that static extension members should be marked as Alias Extender - simply Alias may look vague somehow. I know full well how naive these thoughts are: I'm just a hobbyist .NET programmer, not a VB.NET language designer, and I can't even guarantee that my own source generator won't break. Even if VB.NET's language evolution is out of the question for the moment, I hope my "naivety" can at least become a meaningful footprint in the course of my exam prep.
Imports System.Numerics
Public Module MyExtenders
' Instance extension members (extenders) - the VB counterpart of C#'s extension member syntax:
' extension<T>(T num) where T : INumber<T> { ... }
'
' The extension target is the type parameter itself: any T satisfying `INumber(Of T)`
' gains the members below, invoked on a value (bound here as `num`) as an extender.
Extender num As T When INumber(Of T)
' Remaps `num` from the input range [inMin, inMax] onto the output range [outMin, outMax].
' In other words, an inverse lerp on the input range followed by a lerp on the output range.
Public Function Remap(inMin As T, outMin As T, inMax As T, outMax As T) As T
If T.Compare(inMin, inMax) >= 0 Then
Throw New ArgumentException("inMin must be less than inMax")
ElseIf T.Compare(outMin, outMax) >= 0 Then
Throw New ArgumentException("outMin must be less than outMax")
End If
' Guard against a degenerate input range: if inMax and inMin collapse to the same
' `Double`, skip the division and fall back to the start of the output range.
Dim isEqual As Boolean = Math.Abs(CDbl(inMax) - CDbl(inMin)) < Double.Epsilon
Dim inverseLerp = If(isEqual, 0.0, (num - inMin) / (inMax - inMin))
Return outMin + (outMax - outMin) * inverseLerp
End Function
End Extender
' Static extension members - the VB counterpart of C#'s `extension(Math)` with static methods.
' These attach to the Math type itself, so calling `Math.Deg2Rad(...)` reads no differently
' from `MyExtenders.Deg2Rad(...)` - the alias merely makes Math the nominal host.
Alias Extender Math
' Converts an angle in degrees to radians.
Public Shared Function Deg2Rad(degrees As Double) As Double
Return degrees * (Math.PI / 180.0)
End Function
' Converts an angle in radians to degrees.
Public Shared Function Rad2Deg(radians As Double) As Double
Return radians * (180.0 / Math.PI)
End Function
End Extender
End Module
Thanks for reading this far. Whatever the future holds for VB.NET's evolution, I'll continue to maintain my GitHub projects and NuGet packages right after my exam.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue names no repository files or tests; begin with its VB.NET examples for Trait, Extender, and Alias and compare them with the referenced C# generic-math and extension syntax. A complete contribution would need a scoped language-design decision and an implementation and test plan, none of which is defined here.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- visualbasic
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100