The place for the VB community to join our collective voice! See https://github.com/CommunityVB/Main for more info.
stakx
's word for it. He may be interested in discussing it: https://github.com/moq/moq4/issues/1067#issuecomment-706671833 | @paul1956
I am looking to put a proposal to VB to get some pattern support that fits within the guidelines of what enhancements VB language can get. The first is the declaration pattern. To address the patterns below
Select Case x
Case TypeOf x is Something
Dim y as Something = x
Case TypeOf x is SomethingElse
Dim z as SomethingElse = x
End Select
If TypeOf x is Something then
Dim y as Something = x
End if
What I need to complete it is a VB like syntax that works for both and is extensible. If should be clear for any programmer that can read VB what is happening.
Await
got implemented as both an operator and a statement. On a technicality, your example begins with oErrors...
- i.e. the letter "o" and not "(". In that example, Await
is an operator, forming an expression which then returns an object that (presumably) has a member named Errors
, which in turn gets invoked and returns something that becomes the parameter to the AddRange
member of oErrors
. While the distinctions between "statement" and "expression" tend to get fuzzy in real programming languages (e.g. https://therenegadecoder.com/code/the-difference-between-statements-and-expressions/), in at least the academic sense the differences are meaningful, and some languages enforce this dichotomy more sharply. E.g., C/C++ are super fuzzy, yet Java (although leveraging C/C++ idioms) is decidedly restrictive (and C# follows these Java restrictions).
New
expression to be a statement, and I guess nobody saw a compelling reason to then allow it in the VB.NET design. I do not understand why anything like new some_type();
or new some_type().someMethod();
is a good coding pattern, but I guess the C++ folks have liked it well enough (for whatever reasons of their own) that the Java designers allowed it.
new some_type();
or new some_type().someMethod();
in VB.NET to be anything terrible or atrocious or particularly wasteful.
Imports
and Namespace
come to mind). The Java docs say (simply), FWIW: "Statements are roughly equivalent to sentences in natural languages. A statement forms a complete unit of execution."
@VBAndCs I believe the reason why it works with CALL is that you are essentially passing an expression result (hidden variable) to a function (CALL) - without the CALL keyword, the code appears invalid syntax. Some of this harkens back to the original days of BASIC where each instruction (line) consists of "instruction number, an operation, and an operand." (Quoted from the original BASIC manual circa 1964.) Obviously we eventually moved away from including the instruction number... but the operation and operand pattern actually makes perfect sense. The confusion regarding this very valid pattern came into play when personal computers (due to lack of memory) added the ability to drop the LET keyword - however, it can be argued that it is simply inferred. Anyway the general concept for BASIC is each statement starts with a keyword (except, of course, for variable assignment - one reason why I'd like to see LET return, at least as an option for teaching beginners) - and although New is a keyword... it's really about creating a new variable... thus not a keyword in the sense of the accepted pattern (IMO). I would add that in the specific example, you could also do the following:
If (New PayCheckWnd).ShowDialog = OK Then
...
End If
But again... I'm basically creating a throw-away variable as part of an expression... not a direct non-keyword command.
new
operations, indicates there are moments that something like new some_type();
can be a problem. Not sure about new some_type().someMethod();
though - but then the VB compiler is designed with the expectation of somehow recognizing what sort of statement is being expressed as early as possible.
Public Module EnumExtensions
Private Sub CheckIsEnum(Of T)(withFlags As Boolean)
If Not GetType(T).IsEnum Then
Throw New ArgumentException(String.Format(Globalization.CultureInfo.InvariantCulture, "Type '{0}' is not an enum", GetType(T).FullName))
End If
If withFlags AndAlso Not Attribute.IsDefined(GetType(T), GetType(FlagsAttribute)) Then
Throw New ArgumentException(String.Format(Globalization.CultureInfo.InvariantCulture, "Type '{0}' doesn't have the 'Flags' attribute", GetType(T).FullName))
End If
End Sub
<Extension>
Public Function ClearFlags(Of T As Structure)(value As T, flags As T) As T
Return value.SetFlags(flags, False)
End Function
<Extension>
Public Function ClearFlags(Of T As Structure)(value As T) As T
CheckIsEnum(Of T)(withFlags:=True)
For Each flag As T In [Enum].GetValues(GetType(T)).Cast(Of T)()
value = value.ClearFlags(flag)
Next flag
Return value
End Function
<Extension>
Public Function CombineFlags(Of T As Structure)(flags As IEnumerable(Of T)) As T
If flags Is Nothing Then
Throw New ArgumentNullException(NameOf(flags))
End If
CheckIsEnum(Of T)(withFlags:=True)
Dim lValue As Long = 0
For Each flag As T In flags
Dim lFlag As Long = Convert.ToInt64(flag, Globalization.CultureInfo.InvariantCulture)
lValue = lValue Or lFlag
Next flag
Return DirectCast([Enum].ToObject(GetType(T), lValue), T)
End Function
<Extension>
Public Function GetDescription(Of T As Structure)(value As T) As String
CheckIsEnum(Of T)(withFlags:=False)
Dim name As String = [Enum].GetName(GetType(T), value)
If name IsNot Nothing Then
Dim field As FieldInfo = GetType(T).GetField(name)
If field IsNot Nothing Then
Dim attr As DescriptionAttribute = TryCast(Attribute.GetCustomAttribute(field, GetType(DescriptionAttribute)), DescriptionAttribute)
If attr IsNot Nothing Then
Return attr.Description
End If
End If
End If
Return Nothing
End Function
<Extension>
Public Iterator Function GetFlags(Of T As Structure)(value As T) As IEnumerable(Of T)
CheckIsEnum(Of T)(withFlags:=True)
For Each flag As T In [Enum].GetValues(GetType(T)).Cast(Of T)()
If value.IsFlagSet(flag) Then
Yield flag
End If
Next flag
End Function
<Extension>
Public Function IsFlagSet(Of T As Structure)(value As T, flag As T) As Boolean
CheckIsEnum(Of T)(withFlags:=True)
Dim lValue As Long = Convert.ToInt64(value, Globalization.CultureInfo.InvariantCulture)
Dim lFlag As Long = Convert.ToInt64(flag, Globalization.CultureInfo.InvariantCulture)
Return (lValue And lFlag) <> 0
End Function
<Extension>
Public Function SetFlags(Of T As Structure)(value As T, flags As T, [on] As Boolean) As T
CheckIsEnum(Of T)(withFlags:=True)
Dim lValue As Long = Convert.ToInt64(value, Globalization.CultureInfo.InvariantCulture)
Dim lFlag As Long = Convert.ToInt64(flags, Globalization.CultureInfo.InvariantCulture)
If [on] Then
lValue = lValue Or lFlag
Else
lValue = lValue And (Not lFlag)
End If
Return DirectCast([Enum].ToObject(GetType(T), lValue), T)
End Function
<Extension>
Public Function SetFlags(Of T As Structure)(value As T, flags As T) As T
Return value.SetFlags(flags, True)
End Function
End Module
What's wrong with System.Enum
1.Nearly all of Enum's static methods are non-generic leading to the following issues. ◦Requires the enum type to be explicitly specified as an argument and requires invocation using static method syntax such as Enum.IsDefined(typeof(ConsoleColor), value) instead of what should be value.IsDefined().
◦Requires casting/unboxing for methods with an enum return value, eg. ToObject, Parse, and GetValues.
◦Requires boxing for methods with enum input parameters losing type-safety, eg. IsDefined and GetName.
2.Support for flag enums is limited to just the HasFlag method which isn't type-safe, is inefficient, and is ambiguous as to whether it determines if the value has all or any of the specified flags. It's all by the way.
3.Most of its methods use reflection on each call without any sort of caching causing poor performance.
4.The pattern to associate extra data with an enum member using Attributes is not supported and instead requires users to manually retrieve the Attributes via reflection. This pattern is commonly used on enum members with the DescriptionAttribute, EnumMemberAttribute, and DisplayAttribute.