[Info-vax] BASIC (and Horizon)

Arne Vajhøj arne at vajhoej.dk
Wed Jan 31 10:20:35 EST 2024


On 1/30/2024 11:28 PM, Dave Froble wrote:
> On 1/30/2024 9:40 AM, Chris Townley wrote:
>> On 30/01/2024 07:06, Dave Froble wrote:
>>> I'm amused every time the GoTo bashing begins.
>>>
>>> Not only is there nothing wrong when using a branch operation, when
>>> appropriate, just look at the assembler listings after compilation.  
>>> Branching
>>> is just about all assembler does, as required.
>>>
>>> Now, I won't defend what I and most consider improper use of the poor
>>> misunderstood GoTo statement.
>>>
>>
>> But unless used very carefully, it can create horrible spaghetti like 
>> code, and
>> is also easy to screw up.
>>
>> Using proper structured constructs is much better - easier to read as 
>> well,
>> hence better maintainability.
> 
> Prey tell, what structured construct will perform cleanup and exit?  I 
> always expected a return from routines and such.

Let me try and show some examples.

In VB.NET.

Te first two examples could be done in VMS Basic (obviously
procedural not object oriented) but the last can not.

First with goto:

Imports System

Namespace GoToDemo
     Public NotInheritable Class Luck
         Private Shared rng As New Random()
         Public Shared Function InLuck() As Boolean
             Return rng.NextDouble() > 0.2
         End Function
     End Class
     Public Class X
         Private id As String
         Private Sub New(id As String)
             Me.id = id
             Console.WriteLine("X {0} created", id)
         End Sub
         Public Shared Function Create(id As String) As X
             If Luck.InLuck() Then
                 Return New X(id)
             Else
                 Return Nothing
             End If
         End Function
         Public Sub Close()
             Console.WriteLine("X {0} closed", id)
         End Sub
     End Class
     Public Class Program
         Public Shared Sub Main(args As String())
             Dim o1 As X = X.Create("A")
             If o1 Is Nothing Then
                 Console.WriteLine("Error creating A")
                 GoTo lbl_done
             End If
             Dim o2 As X = X.Create("B")
             If o2 Is Nothing Then
                 Console.WriteLine("Error creating B")
                 GoTo lbl_close1
             End If
             ' 20 lines
             Console.WriteLine("Part 1")
             If Not Luck.InLuck() Then
                 Console.WriteLine("Error during execution")
                 GoTo lbl_close2
             End If
             ' 20 lines
             Console.WriteLine("Part 2")
         lbl_close2:
             o2.Close()
         lbl_close1:
             o1.Close()
         lbl_done:
             Console.ReadKey(True)
         End Sub
     End Class
End Namespace

It is with goto, but I don't think it is a bad use of goto. It just
jumps down to the cleanup code in case of an error.

Next traditional blocks:

Imports System

Namespace BlocksDemo
     Public NotInheritable Class Luck
         Private Shared rng As New Random()
         Public Shared Function InLuck() As Boolean
             Return rng.NextDouble() > 0.2
         End Function
     End Class
     Public Class X
         Private id As String
         Private Sub New(id As String)
             Me.id = id
             Console.WriteLine("X {0} created", id)
         End Sub
         Public Shared Function Create(id As String) As X
             If Luck.InLuck() Then
                 Return New X(id)
             Else
                 Return Nothing
             End If
         End Function
         Public Sub Close()
             Console.WriteLine("X {0} closed", id)
         End Sub
     End Class
     Public Class Program
         Public Shared Sub Main(args As String())
             Dim o1 As X = X.Create("A")
             If o1 IsNot Nothing Then
                 Dim o2 As X = X.Create("B")
                 If o2 IsNot Nothing Then
                     ' 20 lines
                     Console.WriteLine("Part 1")
                     If Luck.InLuck() Then
                         ' 20 lines
                         Console.WriteLine("Part 2")
                     Else
                         Console.WriteLine("Error during execution")
                     End If
                     o2.Close()
                 Else
                     Console.WriteLine("Error creating B")
                 End If
                 o1.Close()
             Else
                 Console.WriteLine("Error creating A")
             End If
             Console.ReadKey(True)
         End Sub
     End Class
End Namespace

No goto's. But I do not consider the code more readable than the
version with goto's. It sort of unnecessarily stretch out the
core logic.

And now the modern way with exceptions:

Imports System

Namespace ExceptionsDemo
     Public NotInheritable Class Luck
         Private Shared rng As New Random()
         Public Shared Function InLuck() As Boolean
             Return rng.NextDouble() > 0.2
         End Function
     End Class
     Public Class XException
         Inherits Exception
         Public Sub New(msg As String)
             MyBase.New(msg)
         End Sub
     End Class
     Public Class X
         Implements IDisposable
         Private id As String
         Public Sub New(id As String)
             If Luck.InLuck() Then
                 Me.id = id
                 Console.WriteLine("X {0} created", id)
             Else
                 Throw New XException("Error creating " & id)
             End If
         End Sub
         Public Sub Dispose() Implements IDisposable.Dispose
             Console.WriteLine("X {0} closed", id)
         End Sub
     End Class
     Public Class Program
         Public Shared Sub Main(args As String())
             Try
                 Using o1 As New X("A")
                     Using o2 As New X("B")
                         ' 20 lines
                         Console.WriteLine("Part 1")
                         If Not Luck.InLuck() Then
                             Throw New XException("Error during execution")
                         End If
                         ' 20 lines
                         Console.WriteLine("Part 2")
                     End Using
                 End Using
             Catch ex As XException
                 Console.WriteLine(ex.Message)
             End Try
             Console.ReadKey(True)
         End Sub
     End Class
End Namespace

Which I think is pretty nice. No goto's but still a compact
core logic.

For the not VB.NET knowledgable:

Using o1 As New X("A")
     ...
End Using

calls o1.Dispose() when the block is exited no matter how it
is exited - normal or exception does not matter Dispose is
always called.

Arne










More information about the Info-vax mailing list