.net.devcity.weekly ---
If you are unable to see the message, visit http://www.devcity.net/newsletter/archive/devcity/devcity20050525.htm

Advertisement

AdvertisementAdvertisement

The newsletter is compiled by DevCity.NET NewsMasters Ged Mead and Mike McIntyre

Advertisement

Table Of Content:

Advertisement
Diary of a .NET Newbie: Random Thoughts

by Ged Mead

Someone posed a question about how to shuffle the numbers 1 to 15 and have them stored in an array in a random order. Always up for a challenge, I did that whirling round three times thing just like WonderWoman when there's a big task coming up .... but it just made me dizzy.
So, after wobbling to my chair, I pulled up the keyboard to see if this approach might do the job:

'  Create a Random object
    Dim Rnd As New Random(Now.Millisecond)

    '  Create 15 numbers and store in arraylist
    Dim iNumbers() As Integer = _
      {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
    Dim alBoxes As New ArrayList
    alBoxes.AddRange(iNumbers)

    '  Create some temp variables for the shuffle
    Dim iToSwitch As Integer
    Dim objToSwitch As Integer
    Dim alTemp As New ArrayList

    '  Do the shuffle
    '  While some still remain...
    While alBoxes.Count > 0
    
        '  Pick a random element index
        iToSwitch = Rnd.Next(0, alBoxes.Count)
        '  Temp store this element
        objToSwitch = CInt(alBoxes(iToSwitch))
        '  Remove the original from the arraylist
        alBoxes.RemoveAt(iToSwitch)
        '  Store the removed element in the temp al
        alTemp.Add(objToSwitch)
    End While

    '  Check that it worked:
    For x As Integer = 0 To alTemp.Count - 1
        Debug.WriteLine(alTemp(x).ToString)
    Next

And it did, although I couldn't totally shake the feeling that maybe it was a bit heavyweight for what was needed.

Creeping scope then crept in to my overactive mind and I started to wonder what would happen if the requirement wasn't just for the straightforward digits 1 to 15, but for 15 unique random numbers within a range of, for instance, 1 to 100,000.

So I had a play around and this seemed to do the trick:

'  Create a Random object
    Dim Rnd As New Random(Now.Millisecond)
    '  An arraylist to hold random values
    Dim alBoxes As New ArrayList
    ' Create a temp variable and assign it a random value within range
    Dim nextNumber As Integer = Rnd.Next(1, 100000)
    '  Now loop through until you have 15 unique numbers within the range
    For i As Integer = 0 To 14
        While (alBoxes.Contains(nextNumber))
            nextNumber = Rnd.Next(1, 100000)
        End While
        '  If unique, add to arraylist
        alBoxes.Add(nextNumber)
    Next

    For x As Integer = 0 To alBoxes.Count - 1
        Debug.WriteLine(alBoxes(x).ToString)
    Next

This seemed to be OK, too. I was on a roll.

And then I thought "What about generating those random numbers but displaying them in ascending numerical order? " (I know, I know - I should get out more!)

At first, I thought I might use a Sortedlist . But when I tried this I didn't get the results I expected. The Contains method filter didn't seem to work and the result I got each time was 15 copies of the same value. I suspect that this is something to do with the difference in the way an arraylist and a Sortedlist are structured; the Sortedlist requiring the addition of a key, but I wasn't too sure what was causing the problem.

However, before I got too deeply involved in a fist fight with the Sortedlist syntax, I realised that I didn't need to go down that route at all. The simple application of the built-in "Sort" method of the arraylist would do the job very nicely, thank you:

Dim nextNumber As Integer = Rnd.Next(1, 100000)
    '  Now loop through until you have 15 unique numbers within the range
    For i As Integer = 0 To 14
        While (alBoxes.Contains(nextNumber))
            nextNumber = Rnd.Next(1, 100000)
        End While
        '  If unique, add to arraylist
        alBoxes.Add(nextNumber)
    Next
    alBoxes.Sort()   

Fortunately, I ran out of time for further experimenting at this point.
Fortunate for me, as I was able to quit while I was winning.
Fortunate for you, otherwise this article might have run to another 30 pages :-}

Happy Coding

- Junior (Ged Mead aka XTab, xtab@vbcity.com)

Larry Blake

Any juggler can tell you: it's easiest to keep a small number of balls in the air. Similarly, it's easiest for a programmer to work with code that has a small number of class-level variables, and where variable scope is obvious.

A quick definition. "Scope" is the context, or lifetime, of an object. It is desirable to keep scope as small as possible, to free memory and other resources when they are no longer needed, and to make your program more maintainable. If you have a counter variable that is used in one subroutine only, its scope should be that subroutine rather than the lifetime of the class.

Proper scope is not just a neatness issue; it can have performance implications. Consider a form that accesses a database. The user types something, then the program reads the database and displays the requested data. The form might be displayed for minutes, but the data access is milliseconds. If the database connection scope is the life of the form, the form will slow down considerably when the application gets more users. (It might also require buying a bigger and more expensive database license.) A quick "in and out" is usually more efficient.

Doing It Wrong

Look at this confusing example:

Public Class MyClass
    Dim g As String        ' can be used anywhere in class

    Private Sub MySub1()
        g = "Hello"        ' changes the MyClass variable g
        MySub2()
        MySub3()
        MySub4(g)
        MySub5(g)
        MessageBox.Show(g)
    End Sub

    Private Sub MySub2()
        g = "Greetings"    ' changes the MyClass variable g
    End Sub

    Private Sub MySub3()
        Dim g As String
        g = "Hi"           ' changes the local MySub3 variable
    End Sub

    Private Sub MySub4(ByRef h As String)
        h = h & " World"   ' changing h changes MyClass g
    End Sub

    Private Sub MySub5(ByVal h As String)
        h = "Howdy"        ' changes a copy, not MyClass g
    End Sub
End Class

What is the value of g in the MessageBox? You can't really tell without reading MySub2, MySub3, MySub4 and MySub5. (I'll address that later, in "Better Code".) But here's how the code is processed:

  1. MySub2 changes the class variable to "Greetings".
  2. MySub3 creates a new variable g, which is local to the Sub. (Using the same name at different levels is very bad practice, but it's important to understand what happens if you do it accidentally.) This local g is set to "Hi", but then it "goes out of scope" when the Sub ends. In other words, "End Sub" destroys the local variable. The class variable remains at "Greetings".
  3. MySub4 takes the class variable as an input parameter (which is really not necessary, since it's available to the class), and then uses it locally with the name h. The routine appends a suffix to h, and because h is a "ByRef" parameter, the changes are passed back to the caller. The class variable is now "Greetings World".
  4. MySub5 is the same as MySub4, except that the parameter is "ByVal". The routine creates a local copy as h, and then changes the value of the local copy only. When the Sub ends, the class variable is still "Greetings World".

ByRef and ByVal

In case you missed that last bit, parameters can be passed as either ByRef or ByVal. In VB.NET, ByVal is the default, and Visual Studio inserts ByVal if you do not specify a parameter type.

ByVal (by value) means that the called routine uses the value purely for input, to start a "one way" conversation. If A calls B (ByVal x), x becomes a temporary variable in B, using what A passed as a starting value. When B ends, so does x (and any changes made to it).

ByRef (by reference) means that the argument is a reference to the actual calling variable. If A calls B (ByRef x), B can change x and the changes are reflected in A. So, MySub4 (ByRef) changes g; MySub5 (ByVal) does not.

Using ByVal allows programmers to treat routines as "black boxes" that don't need to be opened. Parameters passed this way are "safe". If you don't plan to change the value of a parameter in your routine, you should use ByVal. It allows you to keep a smaller scope, and it saves maintenance time later when you have to read a routine to see if it affects the calling routine.

If you need to send a value back to the outer routine, consider using a Function instead of a Sub with ByRef.

Why Use ByRef?

There are some cases where ByRef is preferable. First, reference variable types (e.g. Forms, TextBoxes, etc.) can't be processed with the ByVal model. ByVal t As TextBox doesn't cause a syntax error, but it gets processed as if ByRef was used (changes to t affect the actual textbox, not an in-memory copy). Specifying ByRef is clearer in this case. Arrays are also always treated as ByRef.

There are also cases where the alternative is something like this:

If (SomeFunction(x)) Then       ' ByVal
    x = SomeVerySimilarCode(x)  ' ByVal
    DidIt = True
End If

If the code is especially complex or slow, you could reduce the above to this, using ByRef.

    DidIt = SomeCombinedFunction(x) ' ByRef

Purists might object. It's a judgment call.

Better Code

Here's the original code again, with some improvements. Notice that if I standardize on ByVal, I only need to read MySub1, MyFunc2 and MyFunc4 to see where the value can change.

Private Sub MySub1()
    Dim g As String    ' scope is just MySub1

    g = "Hello"
    g = MyFunc2()      ' using a function, value change is obvious
    MySub3()           ' can't affect g, because scope is MySub1
    g = MyFunc4(g)     ' using a function again
    MySub4(g)          ' using ByVal, so safe.
    MessageBox.Show(g)
End Sub

Advice to VB6 Upgraders

In VB6, parameters could also be ByRef or ByVal, but the default was ByRef if you omitted the keyword. Be aware that this can cause your routines to behave differently in VB.NET. If you have time, see if you can easily make them ByVal, or convert Subs to Functions. You can do this in place in VB6.

Summary

  1. Keep variable scope as short as possible.
  2. Use ByVal where possible on simple variable types.
  3. Use ByRef on reference variables and arrays, as a reminder that VB will be process them that way.
  4. Use Functions to return values, rather than ByRef variables.

Happy programming.

Note: I have updated this article since it appeared in the original newsletter. Thanks to Ben Spencer and Nino Priore for their corrections.

by Mike McIntyre

This is the third in a series of articles which discuss evolving to VB.NET from a previous version of Visual Basic.

To come up with your own 'personal' top 10 reasons to upgrade to Visual Basic.NET you need: 1) a fairly detailed list of the VB.NET, Visual Studio.NET, and .NET Framework features and 2) a basic idea of what can be done with each feature. This will be your ".NET Feature Shopping List" from which you choose the features that you need or want.

From your shopping list you will select just the features that will actually benefit you. To be beneficial to YOU a .NET feature must be: 1) a superior way to do something that can already be done in VBC or; 2) a new capability that is not available in VBC - PLUS the feature must be must be something you need, or will need, in the not-too-distant future.

To get you started with your ".NET Feature Shopping List", this and the next several articles in this series will present some, but not all, of the many features in .NET that MAY be of use to you.

For the most part the features that will be presented are new features that did not exist in Visual Basic 6. The balance of the features presented will be .Net features that provide a superior way to do something that can be done in Visual Basic 6. Superior means new useful capabilities, simpler to use, faster performance, less error prone, and so forth.

.NET TechnologyFeatureExample Benefit
Windows FormsUse inheritance to add data members, properties, methods, and events to controls provided by Microsoft.t Create your own Windows Forms controls without having to start from scratch.
XMLUse the built-in XML serializer to write/read objects as XML to/from a file.Pass objects as XML to other applications. Use it as a new way to persist application data.
ADO.NETUse the DataSet to write/read relational data to/from files.Create a light-weight database for an application.
Visual Studio .NETDevelop DLLs, a Windows Forms application, a Web Forms application, and some web services at the same time in one Visual Studio.NET solution.Develop a common data tier that works with DLLs, a Windows Forms application, a Web Forms application, and some web services.
.NET FrameworkUse the .NET 'Delegate' type to run a background task while a user continues to use the application interface.Create user interfaces that are not blocked by long running processes such as data access.
.NET CLRUse multiple CLR 'AppDomain' objects to create end user applications that can be automatically updated to a newer version from an intranet or internet server.Automate deployment of application updates.
.NET FrameworkUse .Net 'CollectionBase' type instead of VB.NET 'Collection' type to create collections.Create higher performance collections with many new capabilities.
.NET FrameworkMark your code with .NET 'Attribute' types to modify and extend debugging capability.Customize debugging to your programming style and to fit the need each application you program. Find bugs faster.
Windows FormsUse the 'DataGrid' control to create 'drill-down' views of data.Add 'drill-down' views without third-party controls.
SecurityMark your code with .NET 'code access security' attributes to protect your application in an entirely new way.Who doesn't need better application security these days?
.NET CLR'Just-in-Time' compilation to processor specific machine code.Create machine code that compiles optimized to the processor(s) installed on the computer running the code.
.NET FrameworkUse either VB.NET functions or their .NET Framework equivalents depending on which is best for the application you are writing.Write code quicker, that executes faster, and better fits each programming task.
Advertisement
Articles: Recent Articles

Report Sharp Shooter Review

If you want a report generating tool that goes beyond Crystal Reports then Anand Narayanaswamy recommends you take a look at Report Sharp Shooter. Read his review of this product and link to the demonstration download page here. Read the article

GDI+ Graphics At Work (Part 4)

In the latest article in this series, Ged Mead covers one way of creating a 3D Bar Chart. If you want to get stuck into the basics of GDI+ then this set of articles might be a good start point for you. Read the article

Using C# to Create Distribution Lists

For C# afficionados, Muthukumar V has written this article which explains how to access the exchange domain and create a distribution list programmatically using C# and Active Directory. Read the article

http://www.devcity.net/
Advertisement

We encourage you to pass this issue of
.net.devcity.weekly on to anyone you know with an interest in .NET technology and News You Can Compile

Manage Your Subscription Here.

You are currently subscribed as '*EMAIL*' to .net.devcity.weekly.

Click here to unsubscribe.

Thanks for reading!

Contact:
vbCity.com, LLC
4957 Lakemont Blvd SE C4 #331
Bellevue, WA 98006


DevCity.NET is hosted by FullControl.NET

Copyright vbCity.com, LLC 2003. All Rights Reserved.