• byVal vs. byRef (VB.NET)

    Author
    Topic
    #416944

    Can someone explain to me in what kind of real world situation that we need to use ByRef in passing an argument? I understand that ByRef changes the content of the argument when it is passed back to the calling procedure. I need an explanation on why we want (or not want) to do that.

    Thanks

    Viewing 4 reply threads
    Author
    Replies
    • #933973

      You can use ByRef to allow a function to return more than one result.

      For example I had some code that parsed strings. It returned the current “segment” of the string and a pointer to the starting point in the string for the next iteration. One of these was the return value of the function and the other was returned in a ByRef argument.

      StuartR

    • #933979

      I’m not a .NET user, but I’ve written thousands of lines (sigh) of VB 6 code and I have hardly ever used a ByVal argument. Arguments are ByRef by default and I understand they involve less “overhead” or something (i.e., they generally result in more efficient code).

      The main reason to make an argument ByVal is if the called procedure will be changing its value, the calling procedure will be continuing to use the passed variable after the called procedure is finished, and that continued use by the calling procedure should involve the variable with its original value (i.e. the value before the called procedure messed with it). Even in that circumstance you can pass the argument ByRef if you set up the called procedure in a way that the passed variable ends up unchanged (e.g., by having the called procedure assign its value to a 2nd variable and mess with the 2nd variable instead).

      As Stuart noted, ByRef arguments can be extremely useful because they can be output arguments as well as input arguments. Some ByRef arguments function solely as output arguments.

      • #934130

        In .NET, ByVal is more efficient.

        ByRef wrks differently than in VB 6.

        In .Net, when you say

        a = b

        You are not changing a independently of b.

        If then change a, that results in a change in b.

        Why?
        Because everything in .NET is an object.

        If you want to create a copy of b, then you have to use

        a.Clone = b

        Quite different than in VB.

        • #934139

          blush Well, I noted I wasn’t a .NET guy, but probably shouldn’t have done such a fine job of demonstrating it!

          I get the feeling upgrading code from VB6 to .NET is likely to be a many-pots-of-coffee task.

          • #934168

            ByVal is the default in .Net.

          • #934212

            I get by on just OJ and water, each taken separately.

          • #934232

            I’d add my 2cents by saying that I’m entrenched in the traditions on non-.NET also.

            Alan

            • #934249

              It isn’t bad once you make the mental jump. I like it much better than either VBA or VB, but you have to get used to everything being an object., including things like a string variable. Once you DO get used to it, it makes a lot of sense. If you do it right, you tend to write much more loosely coupled code than in VB/VBA, and it’s a dream for n-tier stuff. thumbup

            • #934263

              I actually just had my first serious squizz at a VB.NET article, since I’ll eventually be forced to move out of the dark ages. sad First impressions are that it’s moved closer to the C++ OOP that I’m most comfortable with, so that’s probably a good sign (for me). It also looks like even the primative types (integers for instance) have been wrapped up as objects, which goes even beyond Java’s object orientation as I understand it.

              It looks like “real” inheritance has been addressed (although not the multiple inheritance of C++ ??) , try/catch exception handling, method overloading (and operator overloading ??) and other aspects o polymorphism. This looks pleasingly like pretty familiar territory. smile

              Do you have any recommended links to summary overview of the new features?

              cheers
              Alan

            • #934293

              *All* types are objects and you handle them via their methods and properties. It is object oriented but there are some limits to this version, at least. Overloads are wonderful and there is no longer a real need for optional parameters, although they’re still supported. However, if you DO use Optional, all arguments have to be declared as optional in the routine declaration. I”m not sure I understand why they bothered to keep it, except maybe for backward compatibility. The hardest thing for me to adapt to has been the lack of user-defined types to pass multiple pieces of information at once. You simply don’t do it that way in .Net.

              At the moment, I’m busily writing unit tests for various data entities, and I absolutely LOVE that! Testing the logic before writing code to implement it is wild. Creating tests to uncover bugs in created code is way easier than trying to figure out where an error or weird result came from, and you can fix the bugs before you actually have to use the code that contains them. groovin

              Oops, sorry, I hit the wrong button. I can’t suggest any links because the differences are so vast, I wouldn’t know where to start. I think most of us trying to make the transition, try books, cbt, magazines, forums, etc., and pick it up as we go along. I found that working in it is the best way to really learn it. Of course, it helps to have someone around who knows more about it than you do …. grin

            • #934303

              The hardest thing for me to adapt to has been the lack of user-defined types to pass multiple pieces of information at once. You simply don’t do it that way in .Net.

              You can still define user types or Structures as they are known in VB .NET and pass them as parameters. In fact, Structures are like mini-classes and can contain public methods and can even implement interfaces, however structures lack other OOP functionality that make classes so versatile. Funnily enough for this thread, the key difference between structures and classes is that structures are value types and classes are reference types.

              HOWEVER, and here’s the rub. The CLR does allow a value type to be treated as a reference type. This is because of the System.Object and something called boxing. All objects inherit from System.Object which itself is a reference type.

              Imagine where a function,for example Console.Writeline, lacks a specific overload for, lets say, a Date type (which is a value type) but has an overload for an Object type parameter. If it were possible to coerce the Date type into an Object the function would work just fine.

              What actually happens is that a wrapper for the value type, in this case a Date is created to make it look like a reference type. This wrapper is allocated on the heap and the value type’s value is copied into the wrapper (so a copy is stored in the heap). The system marks the wrapper to identify it as a value type masquerading as a reference type. This process of moving a value type onto the heap and providing a reference type wrapper is known as boxing. The reverse process is known as unboxing. Essentially, the process of boxing and unboxing allows any type to be treated as an object.

              The caveat to all of this is performance. Loading value types onto the heap and generating a wrapper doesn’t come without cost. Not understanding the impact of boxing and when it occurs can introduce performance bugs.

              Consider this code:

              Sub Main()
              Dim i as Integer = 5
              Console.Writeline(“{0}, {1}”, i, i)

              ‘ Manually box the integer
              Dim o As Object = i
              Console.Writeline(“{0}, “{1}”, o, o)
              End Sub

              The first Console.Writeline boxes the integer twice. A more efficient approach is to manually box the integer only once as shown.

              BUT, manual boxing is not always more efficient. There is a perfromance difference if you’re dealing with an immutable value type (Date) versus a mutable type (Integer or Double). If the type to be boxed is immutable you’re better off just passing the variable to a method and allowing the runtime to box it. You’ll see a benefit to manually boxing your variables if you need to pass them repeatedly to functions that would otherwise result in boxing operations each time the variable was marshaled.

              Back to structures. Consider this example of a Point type structure to store coordinate pairs but we want to sort these pairs in order of distance from the origin (coordinates x=0, y=0). The calculation itself is pretty simple but we don’t want to implement a sort algorithm with all of the other logic. The solution can be found in the ICompareable interface. Thus:

              Public Structue MyPoiint
              Implements IComparable
              Public x as Integer
              Public y as Integer

              Public Function CompareTo(obj as Object) As Integer _
              Implements IComparable.CompareTo

              Dim pt as MyPoint = CType(obj, MyPoint)
              Dim d1 as Double = (x^2) + (y^2)
              Dim d2 as Double = (pt.x^2) +(pt.y^2)

              Return CInt(d1 – d2)

              End Function

              End Structure

              We can now compare two MyPoint structures using the IComparable interface. Now let’s say we have an array of MyPoint structures.

              Dim pts() as New MyPoint(100)

              To sort it we only need to use the System.Array.Sort method.

              System.Array.Sort(pts)

              Simple but using the IComparable interface when implemented on a structure would cause a lot of boxing and unboxing. In fact, with this example the boxing and unboxing overhead could very easily make a reference type a far better solution. In other words, because of the boxing overhead a class-based implementation would be far more efficient if you expect the IComparable interface to be used frequently.

              And we all thought programming was simple.

              Regards,
              Kevin Bell

            • #934349

              Yes, and you didn’t even mention the effect of Option Strict on coercing types! evilgrin

            • #934377

              surrender

            • #934321

              Thanks Charlotte. I must start to have a casual dig around, to at least be familiar with the ballpark when I’m forced to play there. Many with whom I work are well into .NET, as I hang on grimly to 98 & VB6.

              Alan

            • #934443

              Hi Charlotte

              I found this article: Copying, Cloning, and Marshalling in .NET, admittedly quite specific, but with a well written overview relevant to the topic of this thread.

              As a newbie, confessedly biased towards C/C++, the first impression I get is that MS has rediscovered the inherent power of C++, and called it .NET! They had the hindsight not to dumb it down like Java tried to, and the wisdom to wrap up the “difficult” power features in “friendlier” syntaxes. This isn’t a critisism BTW; on the contrary, it’s a (hopefully accurate) indicator of what I said earlier – fairly familiar turf (conceptually at least) for C++heads.

              Alan

            • #934464

              I am re-reading a GREAT book by Dan Appleman. I highly recommend it for any VB/VBA programmers wanting to move to VB.NET:
              Moving to VB.NET: Strategies, Concepts and Code

              I read the first edition, and it was helpful. This revised second edition has better explanations and code examples. You can
              download code examples for both VS 2002 and VS 2003 from the web site

    • #934038

      As is stated in the other posts, using ByRef allows a procedure, Sub or Function to modify the value of a passed parameter. .NET by default passes variables by value, ie, ByVal is the default. As a matter of good coding practise you should always specify ByVal or ByRef when declaring parameters to a procedure. To not do so can, and often does, introduce subtle bugs into programs.

      An example of ByRef usage could be the following. Imagine you have created a Function that populates a dataset from a database and you want to return the dataset, along with an indicator of success or failure to the calling program.

      Private Function GetMyDataset(DataSetToReturn as Dataset) As Boolean

      Attempt to fill the dataset

      If the database retrieval failed then
      DataSetToReturn = Nothing
      Return False
      Else
      Return True
      Endif

      This will compile and run fine (as long as no exceptions are thrown) but the calling program won’t actually get the data in the dataset because the parameter is ByVal by default. You must declare the paramater as ByRef to allow the function to modify the parameter.

      In essence, when you pass a paramater by value the compiler creates a local copy when you call the procedure, this is achieved by either putting the actual value on the stack or putting a copy of the object into the local heap and a pointer to it on the stack (Yes I know this is not the complete picture because of Heap considerations but it’s pretty much the truth). When the procedure returns to the calling program the stack pointers are modified so that the data put onto the stack is destroyed so any modifications that are made to it are lost. When you use ByRef a pointer to the paramater is put onto the stack and the compiler generates code to reference that data ‘indirectly’, ie, using the pointer so you are actually modifying the data in the caller.

      As for performance issues, depending on the parameter types and sizes ByVal and ByRef can be equally or unequally efficient.

      For calls to API functions, this is very important as a large number of API functions return data in parameters. In fact, in my experience with the programmers who work for me, this has been the number 1 problem (Marshalling is a close second) when calling API functions from .NET.

      I highly recommend the Microsoft Press book, Designing Enterprise Applications with Microsoft Visual Basic .NET by Robert Ian Oliver (ISBN 0-7356-1721-X) for people who want to call API functions from .NET along with a lot of other very useful information.

      Regards,
      Kevin Bell

    • #934106

      Just to add to what st3333ve said, passing by reference is easier on overheads because it’s only a reference (small pointer) that is passed across, rather than a second copy of whatever the variable happens to hold. The efficiency issue will depend very much on what the program does, but it’s for this reason that arrays (potentially very large) can’t be passed ByVal at all.

      I think that the ByRef default is a good idea, because generally, variables should be passed this way unless there’s a particular reason for needing a second “working” copy. In C/C++ you can pass by ref and use a “constant qualifier” to ensure that the variable remains unaltered:

      FunctionName(myVariable const&);

      I’ve always wondered why VB didn’t embrace this qualifier.

      Alan

    • #934447

      Here’s a post-prehistoric grin reference for VB.NET that addresses the issue in some depth:
      Argument Passing ByVal and ByRef (Visual Basic .NET)

      Alan

      • #934477

        Actually, that’s a very good overview for .Net, where ByVal and ByRef aren’t quite as distinct as in VB/VBA.

        • #934527

          Shouldn’t this all be on the .NET board? smile

          My first hard lesson in ByRef was in WordBasic, where I created an infinite loop by resetting a counter in a Subprocedure that needed to run from 1 to 8 in the main procedure. Ooops. Reboot. It was the first and last email trojan I’ve ever unleashed on my co-workers. Thankfully it was April 1, so they could kinda sorta laugh about it.

          • #934546

            Probably, but it got started here, so we decided to evangelize. grin

        • #934563

          Thanks, I guess I’ll pick up such specific details as I need them… but I like it already! groovin

          Alan

    Viewing 4 reply threads
    Reply To: byVal vs. byRef (VB.NET)

    You can use BBCodes to format your content.
    Your account can't use all available BBCodes, they will be stripped before saving.

    Your information: