Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Cristian FRC
    @cristianlt23
    I wish you all a Merry Christmas and a New Year full of achievements!๐Ÿงก ๐Ÿ’› ๐Ÿ’š ๐Ÿ’™ ๐Ÿ’œ
    Cristian FRC
    @cristianlt23
    @VBAndCs , I missed you, I'm glad you came back!!!
    Mohammad Hamdy Ghanem
    @VBAndCs
    Thanks @cristianlt23 .I am in a c# mode now. Happy new year.
    Luckly, I am dicovering somethings about vb via c#, like the cw snippet, and adding a GetEnumeration inner or extension method to classes to be supported with for each. This allows using this syntax for example
    Foe Each i in (1, 5)
    Mohammad Hamdy Ghanem
    @VBAndCs
    Console.writeline(i)
    Next
    Sorry, GetEnumerator.
    Using gitter app.
    Mohammad Hamdy Ghanem
    @VBAndCs
    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
    Mohammad Hamdy Ghanem
    @VBAndCs
    In c#, 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
    Cory Smith
    @DualBrain

    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.

    Cory Smith
    @DualBrain
    So I suppose the shorter response is simply... why? What problem is this addressing?
    CyrusNajmabadi
    @CyrusNajmabadi
    I agree. Those are all good questions.
    I'm not even really sure what you're trying to do in the c# version.
    (shown in the c# channel)
    Real world cases would be helpful. Thanks!
    Cory Smith
    @DualBrain

    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").

    CyrusNajmabadi
    @CyrusNajmabadi
    Right. Furthermore, we specifically added these features because teh copy-beahvior has been the default for C# structs since 1.0
    We have no such need for classes (talking about other ideas floated in the otehr channel), because classes don't copy.
    So there isn't a need to avoid that issue.
    rskar-git
    @rskar-git

    @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#.

    Cory Smith
    @DualBrain
    @rskar-git Isn't that what https://tooslowexception.com/pinned-object-heap-in-net-5/ is for? Regardless, I don't see how having a "readonly" method in a structure addresses what you describe.
    rskar-git
    @rskar-git

    @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
    Cory Smith
    @DualBrain
    Wouldn't making X and Y read only be a better "signal" to the compiler (as well as insuring that the method isn't capable of making any sort of underlying change) make more sense?
    Cory Smith
    @DualBrain
    Also (for the record) I do foresee "something" needing to be done to improve immutability behavior/interaction in VB (at some point); the reason(s) for immutable are becoming much more visible/common, however the approaches do still feel a little "experimental". Given a little more time I believe we'll be able to see which approach(s) fair better than others thus providing a better picture into what VB should do... where, if it were possible (in a perfect world), would be something that could leverage what already exists rather than introducing new keywords/concepts. Regardless of whether or not that would be a reality (meaning no visible changes - only compiler "magic"), I would prefer the most minimal of approaches to introducing new features to accomplish this goal for a myriad of reasons. Observing how immutable evolves in other languages and the circumstances where they are leveraged, I believe is one of the keys in accomplishing the best outcome... unfortunately it also means taking the "wait and see" position.
    rskar-git
    @rskar-git

    Wouldn't making X and Y read only be a better "signal" to the compiler...

    I have a feeling a real compiler/language designer would say "nope". Real world functions call other functions, and the lack of information on whether those other functions qualify as the "readonly" sort too would squelch any optimizations you might hope for wherever a compiler might otherwise detect a candidate "readonly" member. And even wherever one can get lucky via such tacitly inferred "signals", it'll only be of help to the assembly which contains them. The potential performance gains and memory pressure reductions dissipate once one needs to work through interfaces and other assemblies. Since real world applications often leverage libraries and frameworks, one would easily lose a lot of potential for all that compiler work. So an explicit "readonly" signal is essential for cross-assembly situations to maximize the potential improvements.

    The other reason for an explicit "readonly" signal is to minimize run-time surprises of adverse affects on performance and memory usage. Without an explicit "readonly" and compiler guidance, it may remain obscure as to why new or refactored code made things go poorer.

    ...the reason(s) for immutable are becoming much more visible/common, however the approaches do still feel a little "experimental"...

    That may be true enough for C# and .NET. Even so, the ways in which C++ uses its const keyword to effect its own "readonly" signals is an example of real world non-experimental usage (google on "c++ const correctness"). But no doubt the C#/.NET folks are thinking through on this.

    Cory Smith
    @DualBrain
    ๐Ÿ‘
    Mohammad Hamdy Ghanem
    @VBAndCs
    And finally, I started this to say that readOnly function is a confusing expression, and I prefer Preserve Functionwhich is a must in Preserve ReadOnly Property. But lets hope we need to debate about that someday :)
    CyrusNajmabadi
    @CyrusNajmabadi
    I think this protective copping is a big bug in the language design.
    why? if we don't copy, we would violate safety
    Mohammad Hamdy Ghanem
    @VBAndCs

    why? if we don't copy, we would violate safety

    Can you give an example?

    And how come that a property (which is actually a get function and a set sub) changes the fields of the struct without violating safty?
    CyrusNajmabadi
    @CyrusNajmabadi
    Can you give an example?
    uh...
    definitionally
    if it's readonly... the point is that it can only be read and not written...
    so if you were to mutate it... it would literally violate that
    CyrusNajmabadi
    @CyrusNajmabadi
    e.g. say i have struct Point { public int X, Y; }
    and i have readonly Point _point;
    it better not be possible to mutate _point
    Cory Smith
    @DualBrain
    Public Structure Point
       Public Sub New (x As Integer, y As Integer)
          Me.X = x
          Me.Y = y
       End Sub
       Public ReadOnly Property X As Integer
       Public ReadOnly Property Y As Integer
       Public Overrides Function ToString() As String
          Return $"{X}, {Y}"
       End Function
    End Structure

    To my knowledge the above is a "safe" Structure; where the only "annoyance" would be in the fact that I have to create a Newwhere it would be nice if the With functionality could initialize ReadOnly properties (I haven't attempted this lately, so don't know if it has changed recently to be allowed).

    There are also attributes that provide additional hints (StructLayout) to the compiler (and have been for ages) as to how to handle this structure (in the context of interop - I'm not sure they do anything outside of that scenario). To my knowledge this would be "pinnable" since it's only using blittable types (I could be wrong on this, but assuming...), so an array of this could be created outside of the main GC. (I haven't needed this scenario and the documentation seems a bit confusing on this subject - at least to me.)

    As for passing something like this by reference, that seems like trying to (at least to me) force something that (could potentially) be a value type, thus passable on the stack, into something that should be a reference type. And we already have this... if you want by reference, wouldn't that be a Class?

    Class <> Structure

    They serve two very different purposes and, although they appear to have similar functionality/purpose... they simply don't and we shouldn't try to force them to be "the same".

    Mohammad Hamdy Ghanem
    @VBAndCs
    @CyrusNajmabadi I erased my text as I got confused by @rskar-git example. The issue in his example comes from sending the struct to the String.Format function, which is a ByVal copy. Results will change if the sample is rewritten using string concatenation instead of Interpolated string. So, this is not a protective copy, This is a Val type vrs Ref type example.
    And it is a good point to treat structs in interpolated strings with caution if some parts of the interpolated string do some changes in the struct.
    CyrusNajmabadi
    @CyrusNajmabadi
    The issue in his example comes from sending the struct to the String.Format function, which is a ByVal copy.
    what do you mean?
    which string.Format overload.