The place for the VB community to join our collective voice! See https://github.com/CommunityVB/Main for more info.
Otherwise, if the variable you are testing is not a local variable but instead a property of a class... the class could literally return a different result each and every check.
Alternatively (I believe) this could be resolve by using Select Case
.
If it doesn't would a copy of the value of "someConditon" into "tmp" prior to the If Block, and rename the usage of "someCondition" with on this block to "tmp". Gain that guarentee.
This would only be true if the developer honored this restriction.
is predominantly is lowered to an
If ... Then` structure, so same suitable effect exists. In a "pure" single threaded non-eventing/interuptting evaluation it trivial and can be ignored. In a non-linear evaluation environment it does, so assisting the programmer to have awareness, or code-fix.
If
checking is completely within the context of the If
statements. So multi-threaded code shouldn't be an issue (in this example - which I feel is more common). In the event the value does change, there is a high possibility this was what the developer desired/intended. Now if we talk about properties... the value of the property is controlled by the object and one would have to wonder under what conditions that this would be an issue. In some circumstances, the value changing between the If
statements may actually be desired. There are also two very different Select Case
models (lowering)... as you said there is one that is basically a bunch of individual If
statements while the (ultimately) desired lowering would be the "jump list". To my knowledge, the "jump list" version would evaluate the value once and is significantly faster than and something I tend to try to setup for under normal conditions. If the desire is to make the variable unchanging, there are (of course) mechanisms in place to assist with that as well. But I don't think there is a "blanket" mechanism or even warning that would cover all the scenarios and my gut is telling me this would create more confusion than it would potentially address any sort of pitfall. In other words, I can't imagine how one would look at the code a know whether or not this might be a potential issue across all the possible scenarios that could exist. I could, of course, be missing something... so there is always that. ;-)
and is a code fix possible?
Of course it would be better if intellisense take snippets shortcuts into account.
A nice surprise: @sharwell pointed out that there is an option to trun on this feature!
https://github.com/dotnet/roslyn/issues/37049#issuecomment-998997945
something
, otherthing
) are to be treated as having a single immutable value (or the "value" will not be altered.). Is there enough evidence to support or proof that statement, from the specification.
Imports System.Runtime.CompilerServices
Public Module Tools
<Extension>
Public Iterator Function GetEnumerator(
range As ValueTuple(Of Integer, Integer, Integer)
) As IEnumerator(Of Integer)
Dim start = range.Item1
Dim [end] = range.Item2
Dim [step] = range.Item3
If ([step] > 0) Then
For i = start To [end] Step [step]
Yield i
Next
Else
For i = start To [end] Step [step]
Yield i
Next
End If
End Function
End Module
Sub Main(args As String())
For Each i In (1, 10, 2)
Console.WriteLine(i)
Next
End Sub
readonly
is used with functions and properties to state that they can't change the values of the structure. It is a confusing word, and if VB.NET is meant to have a similar functionality some day, fourthly it can't use this keyword for this purpose, because ReadOnly is already used with properties. Luckily, vb had the perfect keyword for the job: Preserve
, which is used with ReDim to preserve the contents of the array.
public Preserve Overrides Function ToString() As string
Return ""
End Function
I'm having a hard time understanding the purpose/reasoning of this (given the provided context/example)... meaning that it's pretty much given what overriding ToString()
is "supposed" to do. Adding additional keywords/functionality to "enforce" this doesn't seem to make sense. And where would this "preserve" be? At the implementation or the origination site? If at the origination, then what if you (for the circumstances at hand) you did want to "change something" (caching including invalidation). Also, is this for a Structure
or a Class
? You mention structure, so I'll go with that for a moment.
' Take care not to change the structure when implementing the following function...
Public Overrides Function ToString() As String
Return ""
End Function
The above code serves the same purpose... another possibility is...
<ReviewIfChangesToStructureGenerateError()>
Public Overrides Function ToString() As String
Return ""
End Function
Leveraging analyzers and whatever rules your team deems appropriate.
Given that we are talking about a structure and depending on purpose of the structure, changes by the dev to the structure are pretty easy to mitigate/maintain since we are talking about a structure - the implementation details of a structure, by their very nature, is pretty light... it's a Structure
after all (not a Class
).
Additionally, it is possible to set the "properties" of a Structure
to be ReadOnly
. Why not enforce the "no changes allowed" at that level rather than at a method level? It seems odd to me that you would single out individual methods as being "read only" while others potentially not being read only.
To take this from another direction... you are mentioning a potential change to the language based (from what I determine from what you wrote) solely on "C# does this" and you are looking for a way to mirror functionality that another language has for the sake of mirroring. What problem(s) does doing this address? What is being addressed (other than mirroring)? How is this going to help me do my job (better)?
Just because another language does something a particular way (regardless of popularity) doesn't mean that all other languages should follow the same approach.
Both of these links tell you what you can do... but neither provide any reason(s), scenario(s), case(s) as to WHY. Worse still, reading through the documentation it appears that in C# 7 they added this and in subsequent releases added even more "stuff" to shore up the addition of this... and even after all of that there are caveats, compromises and potential gotchas that you have to watch out for. All of this knowledge without once specifying any sort of reason as to why you might want to venture down this particular rabbit hole.
With that said, someone mentioned in the Roslyn channel
readonly
types and members was specifically added to make it easier to pass structs around by reference without accidentally creating copies of them.
OK, so there is now a reason. However, I have to wonder the value of this in something like VB. What circumstance(s) is a VB dev needing something like this where there is such a performance/memory impact that they could encounter where having a copy of a structure is an issue? I can imagine it happening in theory, but really having a hard time thinking of a circumstance like this in practice. Worse still is the fact that in order to "guarantee" that the struct isn't copied, variables are potentially copied within the implementation of the method(s) unless the "variable" (member) is already read only... so unless the member is already read only the copy isn't necessarily completely prevented (meaning there will be an impact "somewhere").
@DualBrain
What circumstance(s) is a VB dev needing something like this where there is such a performance/memory impact that they could encounter where having a copy of a structure is an issue?
Real-time applications, such as 3-D action games, simulators, and emulators, come to mind. High-volume/high-speed/high-throughput batch operations would be another. If there's really no need for things like that to be written in VB, then perhaps VB is OK as-is.
But for folks who do that, the sort of structures needed for these things get large (well over 32 bytes), and usually it's preferable to pre-allocate memory-space for those structures that is outside of a garbage collector's reach, and to access them via references/pointers, for significant gains in performance and substantial reductions in memory pressure.
Anyway, that's what's clearly driving the developments of ref structs, Span<T>/Memory<T>, and this new "readonly" contract for functions, in C#.
@DualBrain
Isn't that what https://tooslowexception.com/pinned-object-heap-in-net-5/ is for?
Keeping instances steady in memory is half the battle. A pinned object heap helps to reduce or eliminate the need for references/pointer-to-pointer computations, which improves performance.
I don't see how having a "readonly" method in a structure addresses what you describe.
The central issue here is the idiom which C# and VB.NET intend to maintain about a value-type when not in a "by-reference" mode: Every access of it is an independent copy. To maintain this "independent copy" idiom, their compilers may employ what has been called "defensive copying".
The "readonly" on a function is a signal to the C# compiler that it can reduce or eliminate the need for "defensive copying", which improves performance and lowers memory pressure. This is really useful for where the structures are going to be only read (e.g. some reference lookup table, the contents of which hardly or never change). This is what makes immutability so darn interesting for some.
(Of course, "readonly" is a contract to not engage in or do anything that may change the state of the structure. Put another way, it is a promise of there being no side-effects as a consequence of calling the "readonly" member. I'm guessing that the C# compiler will do what it can, and issue errors/warnings accordingly, to enforce that contract.)
To see this "defensive copying" for structures in action, checkout this code snippet. Think about what the output will be (the "*_s1" variables), then give it a try. From this one can see how "defensive copying" for a Structure gets results that are quite different from an otherwise equivalent Class.
Structure CoordsStruct
Public Shared ToStringCount As Integer = 0
Public Sub New(x As Double, y As Double)
Me.X = x
Me.Y = y
End Sub
Public Property X As Double
Public Property Y As Double
Public Overrides Function ToString() As String
ToStringCount += 1
X += 1
Return $"({X}, {Y}, {ToStringCount})"
End Function
End Structure
Class CoordsCls
Public Shared ToStringCount As Integer = 0
Public Sub New(x As Double, y As Double)
Me.X = x
Me.Y = y
End Sub
Public Property X As Double
Public Property Y As Double
Public Overrides Function ToString() As String
ToStringCount += 1
X += 1
Return $"({X}, {Y}, {ToStringCount})"
End Function
End Class
Function Foo(ByRef oo As CoordsStruct) As String
Return $"{oo} {oo}"
End Function
Function Foo(oo As CoordsCls) As String
Return $"{oo} {oo}"
End Function
Sub Main()
Dim cs As New CoordsStruct(3, 5)
Dim cs_s1 As String = $"{cs} {cs} {Foo(cs)}"
Dim cs_s2 As String = $"{cs} {cs} {Foo(cs)}"
Dim cs_s3 As String = $"{cs} {cs} {Foo(cs)}"
Dim cc As New CoordsCls(3, 5)
Dim cc_s1 As String = $"{cc} {cc} {Foo(cc)}"
Dim cc_s2 As String = $"{cc} {cc} {Foo(cc)}"
Dim cc_s3 As String = $"{cc} {cc} {Foo(cc)}"
Stop
End Sub