dotnet / vblang

The home for design of the Visual Basic .NET programming language and runtime library.
288 stars 66 forks source link

Un/Checked Expression, and Checked For Loop #461

Open AdamSpeight2008 opened 5 years ago

AdamSpeight2008 commented 5 years ago

Related: #180

Checked Expressions

C# has the the concept of check and unchecked expressions, I think we should also bring into VB.net as well. Implicitly assumed to be Checked expression unless explicitly stated Unchecked, as to retain backwards compatibility, We can do this by introducing a new keyword Checked, that acts like a prefix operator on expressions. eg

Dim value As SByte = SByte.MinValue
Dim result As Byte = unchecked( DirectCast( value, Byte) expr`

This is useful when you explicitly want to cast to and from signed to unsigned types, without thrown an exception.


Checked For Loop

A For-Loop is implicitly unchecked (ie it throws exceptions) about being out of range. By prefixing the control variable with Checked eg For Checked index As Sbyte = SByte.MinValue To SByte,MaxValue Step 2. The control variable is checked to remain within the range stated, this has the side-effect of control variable after the final iteration of the loop, not having a value beyond the end value (SByte.MaxValue in the example). This allows the full range of the value types. eg .MinValue To .MaxValue

This can be achieved by altering the lowering of the for loop, in the checked case.

Rough Lowering for Checked For Loop

Nukepayload2 commented 5 years ago

Checked Expressions

If you need to implement unchecked conversions between Byte and SByte without changing the project settings, you can use the following code. It's as fast as the unchecked CByte operator on .NET Core 2.2 x64.

Module SByteAndByteBitConverter
    <StructLayout(LayoutKind.Explicit)>
    Private Structure SByteByteUnion
        <FieldOffset(0)>
        Dim SByteValue As SByte
        <FieldOffset(0)>
        Dim ByteValue As Byte
    End Structure

    <Extension>
    Public Function AsByte(SByteValue As SByte) As Byte
        Return (New SByteByteUnion With {.SByteValue = SByteValue}).ByteValue
    End Function

    <Extension>
    Public Function AsSByte(ByteValue As Byte) As SByte
        Return (New SByteByteUnion With {.ByteValue = ByteValue}).SByteValue
    End Function
End Module

Usage

Dim sb As SByte = -100
Dim ub As Byte = sb.AsByte
hartmair commented 5 years ago

This has already been vaguely proposed a long time ago, see #84 and I'd like to highlight the example there that has bothered me a lot of dirty workarounds already: Currently you are not able to implement hashing algorithms, see for example What is the best algorithm for an overridden GetHashCode?

AdamSpeight2008 commented 4 years ago

Just updating everyone to say there is a prototype implementation at #41104 for this feature.

paul1956 commented 4 years ago

I was working on a NuGet Library but I love if it were built into the compiler. I am playing with BigInteger which would allow conversion from Byte/SByte all the way to ULong/Long but none of it solves the overflow by the compiler itself.

Dim X as byte = CByte(Long.MaxValue + 1)
' Even Unchecked
Dim Y as Byte =CBtype(UnChecked(Long.MaxValue + 1))
AdamSpeight2008 commented 4 years ago

@paul1956

Module M
    Sub Main()
        Dim i1 As ULong = ULong.MaxValue
        Dim i2 as ULong= Unchecked( i1 + 1UL)
        System.Console.WriteLine(i2)
    End Sub
End Module

Will output 0 to the console. Changing the expression from 1UL to 1 results in an upcast being performed converting both side to Decimal then a downcast. Unchecked will not change that.

AdamSpeight2008 commented 4 years ago

@paul1956 My implementation is more of a proof of concept,

paul1956 commented 4 years ago

@AdamSpeight2008 Based on comment from PR are you going to continue to follow up with this?

AdamSpeight2008 commented 4 years ago

@paul1956 I'll still work on it, even if it is just for my edification.

paul1956 commented 4 years ago

Why not just follow instruction in PR #41104 and get support assuming your implementation provides the needed functionality you would get lots of user support.

hartmair commented 4 years ago

Meanwhile, I've created a nuget package for unchecked integer operations in VB.NET, see nuget package VBMath.Unchecked or Github repository System.Runtime.Extensions.Unchecked.

Using System.Numerics

' this will not throw
Dim value = UncheckedInteger.Add(Integer.MaxValue, 1)