dotnet / vblang

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

Proposal: Variabes, parameters and properties with range validation #464

Open VBAndCs opened 5 years ago

VBAndCs commented 5 years ago

This is a feature I am waiting for for years, even before ASP.NET MVC added some validation attributes to the Model members, and I am wondering why this didn't happen until now!

We can force variables to accept some values only like this:

Dim x As Integer In [20, 40] ' From 10 to 10
Dim y As Integer In {1, 3, 7, 10} ' Discrete values
Dim z As Integer In [20, 40]  Or {1, 3, 7, 10} 
x = 3 ' OK
y = 100 ' Exception
z = 5 ' Exception

This can be lowered to:

Dim x As Integer
Dim y As Integer
x = Assign_x(3)
y = Assign_y(100)
z = Assign_z(5)

Where:

private Function Assign_x(value as integer) As integer
     If value < 20 OrElse value > 40 Then Throw New OverflowException() 
     Return Value
End Sub

private sub Function Assign_y(value As integer) As integer
     If Not {1, 3, 7, 10}.Contains(value) Then Throw New OverflowException() 
    Return Value
End Sub

private Function Assign_z(value As integer) As integer
     If value < 20 OrElse value > 40 Then Throw New OverflowException() 

     If Not {1, 3, 7, 10}.Contains(value) Then Throw New OverflowException() 
    Return Value
End Sub

Note: If the x is set via a ByRef parameter, then the Assign_x should be called when setting that parameter inside the function.

The real benefit of this is to have an easy way to force some constrains over property values and function params:

Function Foo(x As Integer In[1, 10])

End Function

Property Prop1 As String In {"Red", "Green", "Blue"}

In this case, VB can add the validation conditions for the param or the value in the beginning of the function or the Set block. The back field of the property should be validated also.

rskar-git commented 5 years ago

Putting constraints directly on a field or automatic variable probably wouldn't work out on the compiler side. The problem is in how to make sure the constraints get applied reliably, especially in calls to other DLL's. The other issue is one of maintenance; ad-hoc constraints would encourage "magic number" anti-patterns too easily.

Instead, what is generally done is one creates a new data type - a "subtype". Specifically, a subtype scheme for Structure types (a.k.a. value types in .NET). E.g., in Ada

subtype Int       is Integer;
subtype Small_Int is Integer range -10 .. 10;

In Ada, such constraints via subtypes are guaranteed to get strictly enforced.

So what I would be happy to see is maybe some sort of subtype system. But it's unclear to me how this might look in VB. Maybe the Narrowing keyword could be used in conjunction with Structure?

Enum Fruit As Integer
    Apple = 10
    Banana = 22
    Cherry = 300
    Dates = 499
    Elderberry = 543
    Fig = 688
    Grapes = 733
    Honeydew = 877
    Kiwi = 22
End Enum

Structure CulledFruit As Narrowing Fruit Is {Apple, Cherry}

Structure First3Fruits As Narrowing Fruit Is Apple To Cherry

Structure SmallFruits As Narrowing Fruit Is Cherry To Elderberry, {Grapes}

Structure FruitSalad As Narrowing Fruit Is Apple To Cherry, {Grapes, Elderberry, Honeydew}

Structure FavoritesInFruitSalad As Narrowing FruitSalad Is {Apple, Banana, Grapes}

Structure Tenish As Narrowing Integer Is -10 To 10

Structure OddsUpTo20 As Narrowing Double Is {3, 5, 7, 9, 11, 13, 15, 17, 19}

So your example would look something like this:

Structure Valid_x As Narrowing Integer Is -10 To 10
Structure Valid_y As Narrowing Integer Is {1, 3, 7, 10}
Structure Valid_z As Narrowing Integer Is 20 To 40, {1, 3, 7, 10}

Dim x As Valid_x
Dim y As Valid_y
Dim z As Valid_z

x = 3 ' OK
y = 100 ' Exception
z = 5 ' Exception

This could be lowered to something resembling this:

<DebuggerDisplay("{[default].Value}")>
Structure Valid_z
    ' Presumably the lowered code could duplicate this "Implements"
    Implements IComparable, IComparable(Of Valid_z), IConvertible, IEquatable(Of Valid_z), IFormattable

    Public ReadOnly [default] As Int32?
    Public Shared Function Contains(x As Int32) As Boolean
        Return (x >= 20 AndAlso x <= 40) OrElse
            {1, 3, 7, 10}.Contains(x)
    End Function

    Public Sub New(Value As Int32)
        If Contains(Value) Then
            Me.default = Value
        Else
            Throw New ArgumentException()
        End If
    End Sub
    Private Sub New(Value As Int32, ValidFlag As Boolean)
        If ValidFlag Then
            Me.default = Value
        Else
            Throw New InvalidCastException()
        End If
    End Sub

    Public Shared Narrowing Operator CType(x As Int32) As Valid_z
        Return New Valid_z(x, Contains(x))
    End Operator
    Public Shared Widening Operator CType(x As Valid_z) As Int32
        If x.default.HasValue Then Return CType(x.default, Int32)
        Throw New InvalidCastException()
    End Operator

    ' Presumably the lowered code could create various members as needed 
    ' based on whatever is getting subtyped
    Public Shared Function Parse(s As String) As Valid_z
        ' ...
    End Function
    Public Function Equals(obj As Valid_z) As Boolean
        ' ...
    End Function
    ' etc. ...

End Structure

Note the use of Nullable(Of T) (e.g. Int32?) - it would seem in .NET a value type must support being instantiated as all its bits are zeros. Hence the subtype must be nullable to detect this situation, since all zeros might not be valid.

VBAndCs commented 5 years ago

@rskar-git Nice ideas. I wish VB can make use of the best concepts from Ada, F# and TypeScript and assimilate them into VB syntax. VB.NET deserves a new design with a more suitable name, such as CoreBasic (since there is no longer any thing visual in the lang itself, and there will be no .Net Framework any more!)

paul1956 commented 5 years ago

@VBAndCs I am confused VB is very visual and I am running UI applications on Core 3.0 now. The framework work now just on Core. I like the proposal by @rskar-git. But in the the short term focus should be to make sure VB can consume all the .Net core libraries inclusing those that use Span.

VBAndCs commented 5 years ago

The UI framework (WinForms, WPF, UWP or other) has norhing to do with VB. It is a common framework for all .net languages. VB.NET it self is just a compiler with no visual interface. VB6 was a whole product that consist of a compiler and a visual interface.

paul1956 commented 5 years ago

I am not "seeing" the difference with Visual Studio and VB/C# I get a complete UI experience at least until Core 3.0 and that is coming back, and with much pain I can get it today. Not sure what VB6 gave me that I don't have today with Framework.

VBAndCs commented 5 years ago

Sorry, but you miss the concept. There is a Visual Studio and other frameworks that are common to all projects regardless of the language you use. The compilers them selves are not aware of any of those components, and you can use them with command line or build your IDE and other UI components that targets them. C#, F# and Basic have no visual capabilities or instructions. MS sometimes uses the name Visual C#.NET but no one else uses it. Just C#. The BASIC compiler should be the same, and have a more logical name, sucfh as CoreBasic, Basic.Core, B#, or whatever. But of course I don't speak about the renaming only. This should be a rebuild of the language for a new era, having more dynamic capabilities from F# and TypeScript, and some features from Ada and Paython. Another powerfull feature is to allow a general script string interpolation to allow composing and compiling any supported VS.NET language(or script language) to be written directly in VB code like XML literals, with full intelligence support. This will allow VB to use JSON, JavsScript, C#, F#, Paython, HTML, … inline expressions. This should regain the A power of the BASIC: Beginner's All-purpose Symbolic Instruction Code. A new vision of VB can make it a gain the most popular language in the world, and the most Powerful one. I hope we can start this as a community project ourselves. Recently, I read a couple of books about Roslyn, but this is not a one man show.

paul1956 commented 5 years ago

@VBAndCs so pick a feature, clone and branch Roslyn and start work, that is the beauty of Open Source, I didn't like the limitations in comment placement in VB compared to other languages and I changes it. In VB 16 you can put comments almost anywhere because you can put them AFTER an explicit line continuation (though at the moment formatting can get ugly). I have no idea if the maintainers would review or accept your changes, and the process to get a change to the language is very long I started in Feb 2018 and VB 16 is still not officially released at least as the default version (its still 15). The parser for your feature does not look difficult, its the 100's of tests that will need to change or be added and then the code generator (I still have not looked into how that works). I had never used json until yesterday and today I have a colored TreeView to display jason on a RichTextBox, didn't need any VB language support. I did it because I wanted to look at Code Coverage of my application and Coverlet outputs json, Today I worked on a full viewer of VB source highlighted by the output of Coverlet, I would say VB with Winforms is very efficient. Now I need to figure out why Coverlet doesn't fully work with VB but I think someone on the CoreFx team beat me to it.

rrvenki commented 4 years ago

@rskar-git Nice ideas. I wish VB can make use of the best concepts from Ada, F# and TypeScript and assimilate them into VB syntax. VB.NET deserves a new design with a more suitable name, such as CoreBasic (since there is no longer any thing visual in the lang itself, and there will be no .Net Framework any more!)

@VBAndCs @rskar-git, I thought B# (Be Sharp) fits well. But I remember someone in this forum said a similar programming language already exists. I still think VB deserves B# better.

"Be Sharp" should be better than "C Sharp". Read it again and again.

rrvenki commented 4 years ago

I am not "seeing" the difference with Visual Studio and VB/C# I get a complete UI experience at least until Core 3.0 and that is coming back, and with much pain I can get it today. Not sure what VB6 gave me that I don't have today with Framework.

@paul to name some, LinkPoke is so important which could be a potential game changer in IoT world. Bring LinkPoke feature back to B#/VB #383 which is missed now which was available in <VB6.

The same programming model is still used in form of macros in office. In my experience of 22+ years in this field I did not see one company who does not have several XL macros for their inhouse work.

paul1956 commented 4 years ago

LinkPoke as I understand it is an RPC mechanism to transfer the contents of a control, it to me is not a language feature it is a run-time feature and could be added to WinForms using gRPC. At some point the VB WinForms run-time will need a RPC for at least SingleInstance so adding LinkPoke seems doable. If you just want to program VB without WinForms it should run anywhere C# runs the problem VB is more than a language and things we assume are part of VB (besides obvious things like MsgBox, devices, environment...) are really in the run-time. I spent last week trying to figure out why a Core VB program stopped running with no error and no UI and never hit a breakpoint, I took all the application source, wrapped it with a empty framework app and it crashed with a very understandable error, the code that caught the error is not in Core 3.1 or the compiler but is in the WinForms source for 5.0.

rrvenki commented 4 years ago

@paul1956 if LinkPoke can be added to WinForms using gRPC, it looks quite trivial. Can you pls help me with where to startup? How easy to get RPC access in Win10 with VB runtime?

If that was possible, I intend to use this feature in Raspberry with Win10 to access all the 40 pins and extenders to these pins. That would help me program IoT sensors so easily with an event driven model. It seriously opens all new world.

In O365 world I wish to use this feature (LinkPoke) more as the VBA is long dead. Even there MS has brought TypeScript as an alternative to VBA.

I'm heavily into IoT with almost all moved from Raspberry to ESP32. ESP capabilities like http access and Arduino programming model with vbscript is quite handy. All i'm looking for is some way to get VB runtime loaded via a memory card attached to ESP32 and VB runtime supporting LinkPoke will be extraordinary feature. For example our ESP32 based Air monitoring station will be far easy to maintain and support.

paul1956 commented 4 years ago

LinkPoke would be added as a NuGet library build on gRPC.

Here is reference to gRPC for .Net Core https://docs.microsoft.com/en-us/aspnet/core/grpc/?view=aspnetcore-3.1 https://docs.microsoft.com/en-us/aspnet/core/grpc/clientfactory?view=aspnetcore-3.1 gRPC is language agnostic, it looks like you just put in a project reference

Git repo is at https://github.com/grpc/grpc-dotnet

Instructions to install at a service https://devblogs.microsoft.com/aspnet/net-core-workers-as-windows-services/

Also look at http://james.newtonking.com/

paul1956 commented 4 years ago

@rrvenki I ported Worker Example in grpc-dotnet and that was trivial but I ran into an issue that the generator does not support VB. I split the code to put Proto directory in C# project and used it to generate and compile the C#, then linked to C# project. Still need more testing but if it works we have an easy solution.

paul1956 commented 4 years ago

@rrvenki First create the relative proto directory and file using the examples from the git repo above for whatever you want to pass between client/sever. The example port easily except for await foreach which has no direct VB equivalent but I now convert it to a Try Block and ForEach.

Then you do need to create a single C# project and create a reference to it in your VB projects. There is no C# code you write in this project it is autogenerated.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <Protobuf Include="..\Proto\count.proto" GrpcServices="Both" Link="count.proto" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.4" />
    <PackageReference Include="Google.Protobuf" Version="3.12.2" />
    <PackageReference Include="Grpc.Net.ClientFactory" Version="2.29.0" />
    <PackageReference Include="Grpc.Tools" Version="2.29.0" PrivateAssets="All" />
  </ItemGroup>
</Project>
rrvenki commented 4 years ago

@paul1956, Thanks for the posting on LinkPoke. As more and more news comes out against VB i kinda lost interest and in office-work most work have moved away from MS platform except few ASP.NET Core. The last nail on the coffin I heard is @AnthonyDGreen leaving MS in Jan2020 (ref: https://visualstudiomagazine.com/articles/2020/04/10/vbnet-aspnetcore.aspx). However VB is gaining more life from other vendors. Keeping all those news away... I'm quite interested in LinkPoke for many reasons... one of which is interfacing with IoT sensors. During 1998-2000 periods I used LinkPoke in VB form textboxes to connect via RS232 COM ports to read oneway data from Furnaces, SCADA, and other devices. I think if such a feature comes in VB today, the struggle I face to interface with several IoT sensors using extenders and wiring could be much easy to manage. I'd be more keen to help in building LinkPoke modules/addons to interface using WiFi, Bluetooth, Cable, etc. so the apps running on ESP32/Arduino directly connects to sensors world and other computing devices seamlessly in highly abstracted manner. In the coming days I'll follow your instructions given above and try to get up and moving and keep you posted. If you feel I should contribute in any coding or development please let me know. Also please note it is possible to use VBScript in Arduino programming. How tough do you think it would be to use VB.NET instead of VBScript engine inside Arduino? Do you think it is worth trying (VB.NET compiler running in PC can build the binary and push to ESP32/Arduino board right)? So LinkPoke + VB.NET compiler can be a ground breaking platform in IoT world.

paul1956 commented 4 years ago

@rrvenki VB.Net runs on Core, when they released Core 5 Preview 6 they showed the Conways's Game of Life (which I ported from Framework to VB) on Core running on Arm with no changes. If Core runs on Arduino then VB should run. WinForms is not being ported off Windows but I have been successful getting a VB application running on Android using Xamarin with just the UI in C# the logic was all VB, the same VB as the application uses on Windows with a WinForms UI. Microsoft is not adding language features, all VB work right now is in 3 areas, Code Refactoring, Bugs and WinForms in no specific order. LinkPoke is a library that should be language independent, possibly built on gRPC. My Converter now ports gRPC correctly, handles await foreach and handles all the required C# code as a black box.

VBAndCs commented 4 years ago

I was thinking of a solution for this, when I stumbled with #543