none
Overloading and late binding

    Question

  • I'm trying to write a method which takes two object parameters, each of which is inherited from a base type. There are four possible subtypes which each can be, and the exact subtype is not known until runtime, so early binding is not an option. What I'd really like to do is to have 16 short Subs, each of which handles a single pair of types, and I can't see how to do this easily in VB, as you can't use late binding of types to overload a Sub definition. Has anyone here tried this and found a way?

    A first stab at the code is to put the method into the base class, but the code quickly turns into spaghetti and becomes unmaintainable.

    Public Class BaseType

    Sub DoIt(A As BaseType, B As BaseType) Dim AType, BType As Type AType = A.GetType BType = B.GetType If AType Is Type1 Then If BType Is Type1 Then '... ElseIf BType Is Type2 Then '... '... End If ElseIf AType Is Type2 Then '... End If End Sub

    end class

    One can use late binding to handle a single parameter type, and define an overridable sub which has its own version for the type of the first parameter - this cleans the code up a bit.

    Public Class BaseType

    Mustoverride Sub DoIt1(B as BaseType)

    ' and call X.DoIt1(Y) directly instead of DoIt(X,Y)

    EndClass

    Public Class1 Type1

    Overrides Sub DoIt1(B As BaseType) Dim BType As Type BType = B.GetType If BType Is Type1 Then '... ElseIf BType Is Type2 Then '... '... End If End Sub

    End Class

    It's annoying that you can't even use Select Case for objects, which would clean the code up a little, but that's another beef.


    Peter



    • Edited by ptoye Saturday, December 02, 2017 5:04 PM cleaned up code
    Saturday, December 02, 2017 5:01 PM

Answers

  • I'd not considered Interfaces. I'll read up on them. Thanks.

    Peter

    As a working example, have a look at the following then I'll explain what I meant about a "HasA" inheritance type:

    Public Interface ILatLon
        ReadOnly Property Latitude As Double
        ReadOnly Property Longitude As Double
    End Interface
    
    
    
    
    
    Public Class US_Location
        Implements ILatLon
    
        Private _locationName As String
        Private _streetAddress As String = "--"
        Private _city As String = "--"
        Private _state As String = "--"
        Private _latitude As Double
        Private _longitude As Double
    
        Public Sub New(ByVal locationName As String, _
                       ByVal latitude As Double, _
                       ByVal longitude As Double)
    
            If String.IsNullOrWhiteSpace(locationName) Then
                Throw New ArgumentException("The location name cannot be null or empty.")
    
            ElseIf latitude < -90 OrElse latitude > 90 Then
                Throw New ArgumentOutOfRangeException("Latitude", "Impossible coordinate." & vbCrLf)
    
            ElseIf longitude < -180 OrElse longitude > 180 Then
                Throw New ArgumentOutOfRangeException("Longitude", "Impossible coordinate." & vbCrLf)
    
            Else
                _locationName = locationName
                _latitude = latitude
                _longitude = longitude
            End If
    
        End Sub
    
        Public Property City As String
            Get
                Return _city
            End Get
    
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then
                    _city = "--"
                Else
                    _city = value.Trim
                End If
            End Set
        End Property
    
        Public ReadOnly Property Latitude As Double Implements ILatLon.Latitude
            Get
                Return _latitude
            End Get
        End Property
    
        Public ReadOnly Property LocationName As String
            Get
                Return _locationName
            End Get
        End Property
    
        Public ReadOnly Property Longitude As Double Implements ILatLon.Longitude
            Get
                Return _longitude
            End Get
        End Property
    
        Public Property State As String
            Get
                Return _state
            End Get
    
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then
                    _state = "--"
                Else
                    _state = value.Trim
                End If
            End Set
        End Property
    
        Public Property StreetAddress As String
            Get
                Return _streetAddress
            End Get
    
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then
                    _streetAddress = "--"
                Else
                    _streetAddress = value.Trim
                End If
            End Set
        End Property
    End Class
    
    
    
    
    
    Public Class MySharedMethods
        Private Sub New()
        End Sub
    
        Public Enum DistanceUnits
            NA
            Kilometers
            Miles
            NauticalMiles
        End Enum
    
        Public Shared Function _
            GetDistance(ByVal location1 As ILatLon, _
                        ByVal location2 As ILatLon, _
                        Optional ByVal units As DistanceUnits = DistanceUnits.Kilometers) As Double
    
            Dim retVal As Double
    
            If location1 IsNot Nothing AndAlso location2 IsNot Nothing Then
                Dim x As Double = _
                    (Math.Sin(DegToRads(location1.Latitude)) * Math.Sin(DegToRads(location2.Latitude)) + Math.Cos(DegToRads(location1.Latitude)) * _
                     Math.Cos(DegToRads(location2.Latitude)) * Math.Cos(Math.Abs((DegToRads(location2.Longitude)) - (DegToRads(location1.Longitude)))))
    
                If x > 1 OrElse x < -1 Then
                    Return 0
                Else
                    x = Math.Atan((Math.Sqrt(1 - x ^ 2)) / x)
    
                    Dim km As Double = 1.852 * 60.0 * ((x / Math.PI) * 180)
    
                    Select Case units
                        Case DistanceUnits.Kilometers
                            retVal = km
    
                        Case DistanceUnits.Miles
                            retVal = km / 1.609344
    
                        Case DistanceUnits.NauticalMiles
                            retVal = km / 1.852
                    End Select
                End If
            End If
    
            Return Math.Abs(retVal)
    
        End Function
    
        Private Shared Function DegToRads(ByVal degrees As Double) As Double
            Return CDbl(degrees * (Math.PI / 180))
        End Function
    End Class

    Now I'll use it:

    Public Class Form1
        Private Sub _
            Form1_Load(sender As Object, _
                       e As EventArgs) _
                       Handles MyBase.Load
    
            Dim loc1 As New US_Location("Charleston, SC", 32.784618, -79.940918)
            Dim loc2 As New US_Location("Isle Of Palms, SC", 32.819412, -79.734383)
    
            Dim asTheCrowFlies As Double = _
                MySharedMethods.GetDistance(loc1, loc2, MySharedMethods.DistanceUnits.Miles)
    
            Dim sb As New System.Text.StringBuilder
    
            sb.AppendLine("The approximate distance between")
            sb.AppendLine(String.Format("{0} and {1}", loc1.LocationName, loc2.LocationName))
            sb.AppendFormat("is {0:f1} miles.", asTheCrowFlies)
    
            MessageBox.Show(sb.ToString, "Haversine Formula")
    
            Stop
    
        End Sub
    End Class

    Look at the function "GetLocation" and please note the two main parameters used:

    Public Shared Function _
            GetDistance(ByVal location1 As ILatLon, _
                        ByVal location2 As ILatLon, _
                        Optional ByVal units As DistanceUnits = DistanceUnits.Kilometers) As Double

    "location1" and "location2" are instances of a class (it neither knows nor cares what class) which implement the ILatLon interface.

    The function only knows that "by contract" whatever class it is has agreed to implement the two read-only properties of that interface.

    Food for thought. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    • Marked as answer by ptoye Saturday, December 09, 2017 7:06 PM
    Monday, December 04, 2017 3:49 PM
  • I agree that overloading is what I need. But the VB compiler won't allow me to overload objects unless I can tell it at compile time the exact type. Here's some code

      Dim SubClassArray() As BaseType = {S1, S2, S3}
    
       Friend Sub DoTest()
    
        Dim s, s1 As BaseType
    
        For Each s In SubClassArray
          For Each s1 In SubClassArray   
    

    S and S1 are variables of Type BaseType, and you haven't provided an overload for that. 

    You need to sort out how you are actually creating and handling the Triangle, Circle, Square etc objects before worrying about how to call the function to do the intersection.  Are you going to pass the objects in variables of the base type (BaseType) when you call the function or are you going to pass the objects in variables of the derived type (Triangle, Circle, Square etc) when you call the function?   That's the 'context' issue I described above. 

    If you call the function with variables of the derived type then overloading is the way to go.  If you call the function with variables of the base type then there is only one function, and that function has to work out how to handle the objects that were passed.

    Your code above is a mixture, and won't work.  


    • Edited by AcamarMVP Thursday, December 07, 2017 8:43 PM sp
    • Marked as answer by ptoye Saturday, December 09, 2017 3:38 PM
    • Unmarked as answer by ptoye Saturday, December 09, 2017 3:50 PM
    • Marked as answer by ptoye Saturday, December 09, 2017 3:50 PM
    Thursday, December 07, 2017 8:42 PM
  • In modern VB, if late binding is enabled (i.e. Option Strict Off), at least for the file that contains DoIt, then try this:

     

       Sub DoIt(A As BaseType, B As BaseType)

     

          Dim oA As Object = A

          Dim oB As Object = B

     

          ShortSub(oA, oB)

     

       End Sub

     

    Assuming that there are a series of ShortSub routines having the corresponding parameter types Type1, Type2, etc.

    The above single call will perform something similar to your Ifs.




    I don't think this works - see my post on 7th at 4:04 pm. Or have I misunderstood something as usual?

    Peter


    You probably did not try it yet. The late binding must be enabled, DoIt subs must be accessible (e.g. public) and the loop will be:

       For Each s In SubClassArray

          For Each s1 In SubClassArray

             Dim a As Object = s

             Dim b As Object = s1

             BaseType.DoIt(a, b)

          Next

       Next


    • Edited by Viorel_MVP Saturday, December 09, 2017 7:23 PM
    • Marked as answer by ptoye Tuesday, December 12, 2017 12:00 PM
    Saturday, December 09, 2017 7:23 PM
  • According to Language Specification (“Late-Bound Expressions” section), the non-public members are ignored when doing late-binding. Unfortunately, it is not explained why. Seems a limitation of VB.NET. (By the way, in C# such dynamic invocation is not restricted).

    • Marked as answer by ptoye Tuesday, December 12, 2017 12:00 PM
    Monday, December 11, 2017 8:44 PM

All replies

  • In modern VB, if late binding is enabled (i.e. Option Strict Off), at least for the file that contains DoIt, then try this:

     

       Sub DoIt(A As BaseType, B As BaseType)

     

          Dim oA As Object = A

          Dim oB As Object = B

     

          ShortSub(oA, oB)

     

       End Sub

     

    Assuming that there are a series of ShortSub routines having the corresponding parameter types Type1, Type2, etc.

    The above single call will perform something similar to your Ifs.



    • Edited by Viorel_MVP Saturday, December 02, 2017 7:08 PM
    Saturday, December 02, 2017 7:02 PM
  • Peter,

    You don't want to set it up with late binding; that robs performance horribly.

    What you show above is a circular reference. Your base type (abstract or otherwise) needs to define what it is and not in terms of itself.

    Once you have a valid base type then inheritance from that should be straightforward.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, December 02, 2017 8:07 PM
  • I think what you're after is to have a base class that can be *anything*?

    Something like this maybe? (Please note the options used - no late binding):

    Option Strict On
    Option Explicit On
    Option Infer Off
    
    
    Public MustInherit Class MyNewClass
        Private _obj1 As Object
        Private _obj2 As Object
    
        Public Sub New(ByVal obj1 As Object, _
                       ByVal obj2 As Object)
    
            _obj1 = obj1
            _obj2 = obj2
    
        End Sub
    End Class
    
    
    
    
    
    Public Class MyStrings
        Inherits MyNewClass
    
        Public Sub New(ByVal s1 As String, _
                       ByVal s2 As String)
    
            MyBase.New(CType(s1, Object), CType(s2, Object))
        End Sub
    End Class
    
    
    
    
    
    Public Class MyIntegers
        Inherits MyNewClass
    
        Public Sub New(ByVal int1 As Integer, _
                       ByVal int2 As Integer)
    
            MyBase.New(CType(int1, Object), CType(int2, Object))
        End Sub
    End Class


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, December 02, 2017 8:21 PM
  • What I'd really like to do is to have 16 short Subs, each of which handles a single pair of types

    That's polymorphism - a different parameter list defines a different function.

    Option Strict On
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim thisBase As New BaseA
            thisBase.Doit(New BaseA1, New BaseA1)
            thisBase.Doit(New BaseA1, New BaseA2)
            thisBase.Doit(New BaseA2, New BaseA1)
            thisBase.Doit(New BaseA2, New BaseA2)
        End Sub
    End Class
    
    Public Class BaseA
        Public Sub Doit(P1 As BaseA1, P2 As BaseA1)
            MsgBox(P1.ToString & " " & P2.ToString)
        End Sub
    
        Public Sub Doit(P1 As BaseA1, P2 As BaseA2)
            MsgBox(P1.ToString & " " & P2.ToString)
        End Sub
    
        Public Sub Doit(P1 As BaseA2, P2 As BaseA1)
            MsgBox(P1.ToString & " " & P2.ToString)
        End Sub
    
        Public Sub Doit(P1 As BaseA2, P2 As BaseA2)
            MsgBox(P1.ToString & " " & P2.ToString)
        End Sub
    
    End Class
    
    Public Class BaseA1
        Inherits BaseA
        Public Overrides Function ToString() As String
            Return "BaseA1"
        End Function
    End Class
    
    Public Class BaseA2
        Inherits BaseA
        Public Overrides Function ToString() As String
            Return "BaseA2"
        End Function
    End Class
    
    
    

    Saturday, December 02, 2017 9:08 PM
  • and the exact subtype is not known until runtime, so early binding is not an option. ld clean the code up a little, but that's another beef.


    Peter



    You make me curious, how do you know the types at runtime?

    That can only with databases. Maybe are you the 100000001 person who wants to make his generic database tool. Then know, like Frank already wrote, it performs horrible and the chances on errors are high. 

    But maybe it is something complete different so let us know. Now it is as writing that you are gonna travel but don't know if it is by plane or foot and want a map solution therefore. 


    Success
    Cor


    Sunday, December 03, 2017 6:00 AM
  • I don't have the option - the class depends on operator action which can't be compiled!

    Kettering's quote would not appear to be pertinent here.


    Peter

    Sunday, December 03, 2017 12:41 PM
  • That looks like a good idea. Similar to Viorel's above. Thanks.

    Peter

    Sunday, December 03, 2017 12:44 PM
  • This looks good - I'll try it out. I hadn't realised that it would work by using Object rather than a base type. Thanks.

    Peter

    Sunday, December 03, 2017 12:45 PM
  • Your analogy of travel is a good one - it's a similar idea (completely different of course). The operator will input what sort of travel he's doing and the type of map he wants, and DoIt will produce the goods. Nothing to do with databases - I can assure you.

    Peter

    Sunday, December 03, 2017 12:48 PM
  • Your analogy of travel is a good one - it's a similar idea (completely different of course). The operator will input what sort of travel he's doing and the type of map he wants, and DoIt will produce the goods. Nothing to do with databases - I can assure you.

    Peter

    Than it has in my perception nothing to do with late binding. 

    The operator knows what sort of travel so calls the right method. If you think he is not able to do that, than it is about AI. But that is no late binding moreover, like I already wrote. It has nothing to do with it. 

    https://en.wikipedia.org/wiki/Artificial_intelligence

    I'm glad to tell that I know from the Visual Studio Tool bellow nothing

    https://marketplace.visualstudio.com/items?itemName=ms-toolsai.vstoolsai-vs2017



    Success
    Cor

    Sunday, December 03, 2017 4:34 PM
  • Cor,

    I think you're taking the analogy a little too far. It has nothing to do with AI. Just that until it's called a subroutine has no idea exactly what subtypes it's dealing with, so has to be called with the base type as parameter. Then it examines the data structure and finds other similar objects which have to interact, so I need to be able to call the interaction code with two parameters of subtype.

    There are other ways of doing it, of course, but I was interested in trying to reduce the amount of explicit coding. And the replies above have indicated ways of doing it, which I hope to have time to examine tomorrow.


    Peter

    Sunday, December 03, 2017 6:54 PM
  • Cor,

    I think you're taking the analogy a little too far. It has nothing to do with AI. Just that until it's called a subroutine has no idea exactly what subtypes it's dealing with, so has to be called with the base type as parameter. Then it examines the data structure and finds other similar objects which have to interact, so I need to be able to call the interaction code with two parameters of subtype.

    There are other ways of doing it, of course, but I was interested in trying to reduce the amount of explicit coding. And the replies above have indicated ways of doing it, which I hope to have time to examine tomorrow.


    Peter

    Peter,

    Add one more possible way to your repertoire then: With an interface.

    An interface provides you with a different form of inheritance; instead of an "IsA" relationship, it's a "HasA" relationship.

    I don't know if it's applicable here but something to consider anyway.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Sunday, December 03, 2017 6:58 PM
  • Just that until it's called a subroutine has no idea exactly what subtypes it's dealing with, so has to be called with the base type as parameter.

    This is the conclusion that is restricting your options.  The two things (not knowing the types, inheritance) are not connected in the way that you imply they are.

    Sunday, December 03, 2017 8:54 PM
  • Add one more possible way to your repertoire then: With an interface.


    I'd not considered Interfaces. I'll read up on them. Thanks.

    Peter

    Monday, December 04, 2017 2:35 PM
  • Just that until it's called a subroutine has no idea exactly what subtypes it's dealing with, so has to be called with the base type as parameter.

    This is the conclusion that is restricting your options.  The two things (not knowing the types, inheritance) are not connected in the way that you imply they are.

    I'm afraid I don't really understand this. If the parameter type isn't known at compile time, you can't specify it! What other type should I use, then? It seems from the comments above that Object is the answer. But as the base type inherits from Object in any case, it seems a little odd that I can't use it. But, hey, that's language design.

    Peter

    Monday, December 04, 2017 2:41 PM
  • I'd not considered Interfaces. I'll read up on them. Thanks.

    Peter

    As a working example, have a look at the following then I'll explain what I meant about a "HasA" inheritance type:

    Public Interface ILatLon
        ReadOnly Property Latitude As Double
        ReadOnly Property Longitude As Double
    End Interface
    
    
    
    
    
    Public Class US_Location
        Implements ILatLon
    
        Private _locationName As String
        Private _streetAddress As String = "--"
        Private _city As String = "--"
        Private _state As String = "--"
        Private _latitude As Double
        Private _longitude As Double
    
        Public Sub New(ByVal locationName As String, _
                       ByVal latitude As Double, _
                       ByVal longitude As Double)
    
            If String.IsNullOrWhiteSpace(locationName) Then
                Throw New ArgumentException("The location name cannot be null or empty.")
    
            ElseIf latitude < -90 OrElse latitude > 90 Then
                Throw New ArgumentOutOfRangeException("Latitude", "Impossible coordinate." & vbCrLf)
    
            ElseIf longitude < -180 OrElse longitude > 180 Then
                Throw New ArgumentOutOfRangeException("Longitude", "Impossible coordinate." & vbCrLf)
    
            Else
                _locationName = locationName
                _latitude = latitude
                _longitude = longitude
            End If
    
        End Sub
    
        Public Property City As String
            Get
                Return _city
            End Get
    
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then
                    _city = "--"
                Else
                    _city = value.Trim
                End If
            End Set
        End Property
    
        Public ReadOnly Property Latitude As Double Implements ILatLon.Latitude
            Get
                Return _latitude
            End Get
        End Property
    
        Public ReadOnly Property LocationName As String
            Get
                Return _locationName
            End Get
        End Property
    
        Public ReadOnly Property Longitude As Double Implements ILatLon.Longitude
            Get
                Return _longitude
            End Get
        End Property
    
        Public Property State As String
            Get
                Return _state
            End Get
    
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then
                    _state = "--"
                Else
                    _state = value.Trim
                End If
            End Set
        End Property
    
        Public Property StreetAddress As String
            Get
                Return _streetAddress
            End Get
    
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then
                    _streetAddress = "--"
                Else
                    _streetAddress = value.Trim
                End If
            End Set
        End Property
    End Class
    
    
    
    
    
    Public Class MySharedMethods
        Private Sub New()
        End Sub
    
        Public Enum DistanceUnits
            NA
            Kilometers
            Miles
            NauticalMiles
        End Enum
    
        Public Shared Function _
            GetDistance(ByVal location1 As ILatLon, _
                        ByVal location2 As ILatLon, _
                        Optional ByVal units As DistanceUnits = DistanceUnits.Kilometers) As Double
    
            Dim retVal As Double
    
            If location1 IsNot Nothing AndAlso location2 IsNot Nothing Then
                Dim x As Double = _
                    (Math.Sin(DegToRads(location1.Latitude)) * Math.Sin(DegToRads(location2.Latitude)) + Math.Cos(DegToRads(location1.Latitude)) * _
                     Math.Cos(DegToRads(location2.Latitude)) * Math.Cos(Math.Abs((DegToRads(location2.Longitude)) - (DegToRads(location1.Longitude)))))
    
                If x > 1 OrElse x < -1 Then
                    Return 0
                Else
                    x = Math.Atan((Math.Sqrt(1 - x ^ 2)) / x)
    
                    Dim km As Double = 1.852 * 60.0 * ((x / Math.PI) * 180)
    
                    Select Case units
                        Case DistanceUnits.Kilometers
                            retVal = km
    
                        Case DistanceUnits.Miles
                            retVal = km / 1.609344
    
                        Case DistanceUnits.NauticalMiles
                            retVal = km / 1.852
                    End Select
                End If
            End If
    
            Return Math.Abs(retVal)
    
        End Function
    
        Private Shared Function DegToRads(ByVal degrees As Double) As Double
            Return CDbl(degrees * (Math.PI / 180))
        End Function
    End Class

    Now I'll use it:

    Public Class Form1
        Private Sub _
            Form1_Load(sender As Object, _
                       e As EventArgs) _
                       Handles MyBase.Load
    
            Dim loc1 As New US_Location("Charleston, SC", 32.784618, -79.940918)
            Dim loc2 As New US_Location("Isle Of Palms, SC", 32.819412, -79.734383)
    
            Dim asTheCrowFlies As Double = _
                MySharedMethods.GetDistance(loc1, loc2, MySharedMethods.DistanceUnits.Miles)
    
            Dim sb As New System.Text.StringBuilder
    
            sb.AppendLine("The approximate distance between")
            sb.AppendLine(String.Format("{0} and {1}", loc1.LocationName, loc2.LocationName))
            sb.AppendFormat("is {0:f1} miles.", asTheCrowFlies)
    
            MessageBox.Show(sb.ToString, "Haversine Formula")
    
            Stop
    
        End Sub
    End Class

    Look at the function "GetLocation" and please note the two main parameters used:

    Public Shared Function _
            GetDistance(ByVal location1 As ILatLon, _
                        ByVal location2 As ILatLon, _
                        Optional ByVal units As DistanceUnits = DistanceUnits.Kilometers) As Double

    "location1" and "location2" are instances of a class (it neither knows nor cares what class) which implement the ILatLon interface.

    The function only knows that "by contract" whatever class it is has agreed to implement the two read-only properties of that interface.

    Food for thought. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    • Marked as answer by ptoye Saturday, December 09, 2017 7:06 PM
    Monday, December 04, 2017 3:49 PM
  • I'm afraid I don't really understand this. If the parameter type isn't known at compile time, you can't specify it! What other type should I use, then? It seems from the comments above that Object is the answer. But as the base type inherits from Object in any case, it seems a little odd that I can't use it. But, hey, that's language design.

    Peter

    You can use an object (be aware it is the name of the Base Class of .Net) an object can be everything like a house a car or whatever. 

    That class (object) has members, one of those as example is the method .ToString. Normally it returns the name as the class as string. 

    However, it is often overriden, for instance for value types, there it returns probably with a kind of polymorphism (Acamar wrote about that), depending on the type a way to show the value of the value type in a more readable way. 

    Normally you can give to a method the type of the class, that is the fastest way. If you don't give it then there is reflection used to guess what the type in the assembly can be. That has the name late (type) binding.

    As is written in this thread already, it takes time. VB6 and scripting languages do it that way. It is exactly the difference with OOP. That is the main reason why those programs (C++, Java, C#, VB since version 7,F#) run faster. 

    Beside that it takes time, it can be risky. If there are two types with the same name in an assembly in standard .Net reflection, the first is taken. 



    Success
    Cor


    Monday, December 04, 2017 4:52 PM

  • I deleted this message because there seems again bugs in this forum. 

    My latest reply became for this and I think this message the OP won't understand seen his last reply. 

    Monday, December 04, 2017 4:53 PM
  • @ptoye - not clear what you are doing, but Generics might help.  A short example.

    Public Class Form1
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Dim a As New Atype
            Dim b As New Btype
            Dim x As New Xtype
    
            Dim base As New BaseType
    
            base.SomeSub(a, b)
            base.SomeSub(a, x)
            base.SomeSub(b, x)
    
            x.SomeSub(a, x)
        End Sub
    
    End Class
    
    Public Class BaseType
        Public tot As Integer = 0
    
        Public Sub SomeSub(Of t, z)(argt As t, argz As z)
            Dim tobj As Object = argt
            Dim zobj As Object = argz
    
            Select Case True
    
                Case TypeOf argt Is Atype AndAlso TypeOf argz Is Btype
                    tot = DirectCast(tobj, Atype).A + DirectCast(zobj, Btype).B
    
                Case TypeOf argt Is Atype AndAlso TypeOf argz Is Xtype
                    tot = DirectCast(tobj, Atype).A + DirectCast(zobj, Xtype).X
    
                Case TypeOf argt Is Btype AndAlso TypeOf argz Is Xtype
                    tot = DirectCast(tobj, Btype).B + DirectCast(zobj, Xtype).X
    
                Case Else
                    Stop
    
            End Select
        End Sub
    End Class
    
    Public Class Atype : Inherits BaseType
        Public A As Integer = 2
    End Class
    
    Public Class Btype : Inherits BaseType
        Public B As Integer = 3
    End Class
    
    Public Class Xtype : Inherits BaseType
        Public X As Integer = 5
    End Class


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it" - MSDN User JohnWein

    Monday, December 04, 2017 4:54 PM
  • I'm afraid I don't really understand this. If the parameter type isn't known at compile time, you can't specify it!

    If you are calling a method which is overloaded so that every possible combination of parameter types already exists (the "16 short Subs, each of which handles a single pair of types" that you referred to) then you don't need to know the type - the appropriate implementation of the method will be selected.  That part of your question is not associated with inheritance, and trying to tie inheritance into it is going to confuse things. Anytime someone uses the term 'subtypes' I suspect that they are implying more into the inheritance relationship than really exists.

    Monday, December 04, 2017 8:31 PM
  • The function only knows that "by contract" whatever class it is has agreed to implement the two read-only properties of that interface.

    Food for thought. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Definitely food for thought. This is taking up far more of my time, and yours than I'd hoped - it's only a sideline and I didn't want to spend more than an hour a day on it. I think the best thing is to restate the question in a bit more detail, but that will be the subject of a separate post.

    Peter

    Tuesday, December 05, 2017 12:56 PM
  • I'm afraid I don't really understand this. If the parameter type isn't known at compile time, you can't specify it!

    If you are calling a method which is overloaded so that every possible combination of parameter types already exists (the "16 short Subs, each of which handles a single pair of types" that you referred to) then you don't need to know the type - the appropriate implementation of the method will be selected.  That part of your question is not associated with inheritance, and trying to tie inheritance into it is going to confuse things. Anytime someone uses the term 'subtypes' I suspect that they are implying more into the inheritance relationship than really exists.


    Well, I'm sorry if my use of "subtype" is against your principles. What other word should I have used? As I said in my reply to Frank Smith's comment I'll have to submit a more detailed post, but don't have time now.

    Peter

    Tuesday, December 05, 2017 1:00 PM
  • Well, I'm sorry if my use of "subtype" is against your principles. What other word should I have used?

    It may be that you're talking about a nested class:

    Class Diagram


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Tuesday, December 05, 2017 2:08 PM
  •   I think the best thing is to restate the question in a bit more detail, but that will be the subject of a separate post.

    Peter

    OK - here it is now I've had time to think (and have lunch).

    Consider a graphics program (odd how often discussions of OO programming use this example) which can handle a number of differently-shaped objects: circles, triangles, rectangles etc. These can be implemented by having a class Shape which contains the common elements: colour, border style etc., and subclasses (or derived classes or whatever you want to call it - I'm not getting into a nomenclature war): Circle, Rectangle etc. which contain the specific shape-dependent properties (position, radius, X/Y size etc).

    Now consider a program which asks the user to select a particular pair of shapes on the drawing board and calculates the area of the intersection. This will need two parameters but the exact type of them is not known at compile time. My original idea was to have overloaded (or polymorphic) methods (subroutines, functions....) which take two subclasses as parameters: GetArea(C as Circle, R as Rectangle) each of which does its own trigonometry to return the result. But, as has been pointed out to me many times in the last week, not least by the VB compiler, this doesn't work. Hence my original question.

    Does this make things clearer?

    Peter

    Tuesday, December 05, 2017 3:36 PM

  • Now consider a program which asks the user to select a particular pair of shapes on the drawing board and calculates the area of the intersection. This will need two parameters but the exact type of them is not known at compile time.

    Yes the type will be known. A standard "IsA" inheritance will do that:

    It's a type "Shape", for example.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Tuesday, December 05, 2017 3:43 PM
  • You don't want to set it up with late binding; that robs performance horribly.

    I'm not so sure about that Frank. I did an experiment comparing late-bound method calling and explicit method calling and found very little difference. I can post the code if you like.

    I also compared it with statements like

    If TypeOf s Is Sub1 

    and

    if S.GetType = S1.GetType 
    which I agree are hopelessly inefficient.

    Peter

    Tuesday, December 05, 2017 3:44 PM

  • Now consider a program which asks the user to select a particular pair of shapes on the drawing board and calculates the area of the intersection. This will need two parameters but the exact type of them is not known at compile time.

    Yes the type will be known. A standard "IsA" inheritance will do that:

    It's a type "Shape", for example.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    But knowing that a parameter is a Shape doesn't give the program enough information to calculate the area. For that you need to know the exact type. And that's what I was trying to do, so that the Circle class would have a GetArea(S as Rectangle), GetArea(S as Triangle) etc. I know that I can do it with if TypeOf(S) is Circle, but as you pointed out, that's inefficient. I was hoping that the runtime system would be able to be more efficient than this - see my comment about efficiency.

    You mention "IsA" - that doesn't seem to be a VB keyword - at least I can't find it in the VB guide on the web https://docs.microsoft.com/en-us/dotnet/visual-basic/ and a search doesn't find it (but it might be too short for the search engine). Now I'm really confused :(


    Peter

    Tuesday, December 05, 2017 4:23 PM
  • You don't want to set it up with late binding; that robs performance horribly.

    I'm not so sure about that Frank. I did an experiment comparing late-bound method calling and explicit method calling and found very little difference.

    I'm sure that for some situation it won't be a lot, but it depends on how deeply it has to "guess".

    I'm still not following what you're actually trying to do but it sounds like classic OOP is the answer here.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Tuesday, December 05, 2017 4:24 PM


  • You mention "IsA" - that doesn't seem to be a VB keyword - at least I can't find it in the VB guide on the web https://docs.microsoft.com/en-us/dotnet/visual-basic/ and a search doesn't find it (but it might be too short for the search engine). Now I'm really confused :(


    Peter

    No, that's a metaphor; it's just simple inheritance.

    This is a good starting point:

    https://blogs.msmvps.com/deborahk/basic-pillars-of-an-object-oriented-system/

    A little more can be found here:

    http://www.codemag.com/Article/0505031

    Do some research and you'll find a lot of information about inheritance.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Tuesday, December 05, 2017 4:28 PM
  • You mention "IsA" - that doesn't seem to be a VB keyword - at least I can't find it in the VB guide on the web https://docs.microsoft.com/en-us/dotnet/visual-basic/ and a search doesn't find it (but it might be too short for the search engine). Now I'm really confused :(


    Peter


    An ellipse "is a" shape. A triangle "is a" shape, and so on.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Tuesday, December 05, 2017 4:35 PM
  • Peter,

    When you can, read the following (and, for that matter, the whole article):

    https://www.codeproject.com/Articles/1218246/Object-Oriented-Programming-Concepts-for-Professio#outside-the

    That's not an easy read - or it wasn't for me at least - but muddle through it. The section that the bookmark should take you to will lead to inheritance and he has a few thoughts on inheritance that I can't help but agree with:

    *****

    " It sounds logical and one cannot stand without cheering and clapping for the above design. This is how you read in other blogs and books. This is good for a beginner. But the problem is that real life problems are hardly like that.

    Real world problems are complex. Real life problems evolve. Therefore if you are using inheritance to model real problems these hierarchies will also evolve.

    I have seen systems where developers life is consumed in managing large hierarchies of inheritance. Managing inheritance hierarchies is a cumbersome task. If you don’t believe me then try using inheritance for next 6 months in your current project and you will know why it is a rigid approach. On the other hand, composition is more flexible in adopting changes.

    I am not saying that inheritance is altogether bad and you should not be doing it. But as a beginner, the inheritance look charming as you can see the above vehicle and car example. This leads to misuse or overuse of inheritance.

    There are some great uses of inheritance and there are some drawbacks to the composition. But for beginners and for a clean code you should focus more on composition instead of inheritance."


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Tuesday, December 05, 2017 5:06 PM

  • An ellipse "is a" shape. A triangle "is a" shape, and so on.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Sorry - I thought you were talking about a language construction, not a principle.

    Peter

    Tuesday, December 05, 2017 7:13 PM

  • https://www.codeproject.com/Articles/1218246/Object-Oriented-Programming-Concepts-for-Professio#outside-the

    That's not an easy read - or it wasn't for me at least - but muddle through it. The section that the bookmark should take you to will lead to inheritance and he has a few thoughts on inheritance that I can't help but agree with:


    It's certainly not an easy read - the English is idiosyncratic to say the least! (Lesson 1: don't try to write in a language which isn't your first, and don't rely on Google Translate - I've got some hilarious examples including a TV set whose manual says that there is a danger of death if using this device).

    At least I pass his first criterion: I was writing code for over 10 years (not in an OO language - that hadn't been invented, apart from Simula AFAIK). But I'm not writing for money, so maybe that bars me :( Just trying to experiment with VB and get something interesting to work. And finding a stumbling-block. I know that I can recode what I want without running into inheritance issues. And will probably do so when I have the time. Experimenting is half the fun.


    Peter

    Tuesday, December 05, 2017 7:26 PM
  • ... I've got some hilarious examples including a TV set whose manual says that there is a danger of death if using this device).

    If you've not seen this before, please take 20 minutes or so to watch it:

    https://www.ted.com/talks/luis_von_ahn_massive_scale_online_collaboration#t-669

    It's a TED talk about how the CAPTCHA and later RECAPTCHA came about (which is interesting) but he then later discusses why computers can't [yet] do a good job of translating languages.

    In particular, he'll talk about a forum post and JavaScript about halfway through.

    It's worth your while to watch. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering


    • Edited by Frank L. Smith Tuesday, December 05, 2017 8:11 PM ... link
    Tuesday, December 05, 2017 7:49 PM
  • This will need two parameters but the exact type of them is not known at compile time. My original idea was to have overloaded (or polymorphic) methods (subroutines, functions....) which take two subclasses as parameters: GetArea(C as Circle, R as Rectangle) each of which does its own trigonometry to return the result. But, as has been pointed out to me many times in the last week, not least by the VB compiler, this doesn't work.

    That is what I posted above: a series of methods with the same name but different parameter lists.  So you can write code like
      Dim R0 As Rectangle = GetArea(myCircle, mySquare)
      Dim R1 As Rectangle = GetArea(mySquare, myTriangle)

    and that code will work with any combination of those classes because you have defined an overloaded function that copes with each combination - the 16 short subs in your original description.   You should indicate why you believe this won't work.

    Your original code would have looked like:

      Dim R0 As Rectangle = DoIt(CType(myCircle, Shape), CType(mySquare, Shape)
      Dim R1 As Rectangle = DoIt(CType(mySquare, Shape), CType(myTriangle, Shape)

    and there would be one function with a parameter list of (Shape, Shape).  That function would examine the type of the argument passed, convert the Shape objects back to their original types, and select the appropriate code to do the calculation according to the types.   That code does not use overloading, but it does require that the shapes are all derived directly or indirectly) from a common base class.     

    The point I made above is that that the first solution has no connection to inheritance, and the second has no connection to overloading.  You original description implied that both were required, when in fact it is one or the other, according to preference.

    If you have other reasons for handling the derived types as their base type - for instance, when the user selects a portion of the image the code only needs to know they have selected a Shape object - then it probably makes sense to handle the objects as that base type all the way through to the intersection calculation, and work out in that routine how to calculate the intersection according to their actual types.  But if the code has to know the actual type at the time that the user makes the selection, then there is little point in converting back to their base type so that the routine can work out what type they really are, and overloading would be simpler.

    From your description it seems that overloading is a better fit to your case.   There is no reason it won't work, and I don't think anyone here has said that it won't.

    Tuesday, December 05, 2017 8:40 PM
  • This will need two parameters but the exact type of them is not known at compile time. My original idea was to have overloaded (or polymorphic) methods (subroutines, functions....) which take two subclasses as parameters: GetArea(C as Circle, R as Rectangle) each of which does its own trigonometry to return the result. But, as has been pointed out to me many times in the last week, not least by the VB compiler, this doesn't work.


    Sorry I didn't reply to your earlier posts - this is taking up too much of my time to sort out and it's very kind of everyone here to be helping me. It's just a bit overwhelming at the moment. I'm obviously going to try out your suggestion , but it won't be for a few days now. I'll report back when I have anything useful to say (and I hope not before).

    Peter

    Wednesday, December 06, 2017 12:38 PM
  • If you've not seen this before, please take 20 minutes or so to watch it:

    https://www.ted.com/talks/luis_von_ahn_massive_scale_online_collaboration#t-669


    Very interesting, but a bit off-topic! I had no idea I was helping to make money for Google (or is it Amazon?) every time I logged in to some sites using reCAPCHA.

    Peter

    Thursday, December 07, 2017 3:50 PM
  • Very interesting, but a bit off-topic!

    It is - I couldn't resist though. ;-)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, December 07, 2017 4:02 PM
  • That is what I posted above: a series of methods with the same name but different parameter lists.  So you can write code like
      Dim R0 As Rectangle = GetArea(myCircle, mySquare)
      Dim R1 As Rectangle = GetArea(mySquare, myTriangle)

    and that code will work with any combination of those classes because you have defined an overloaded function that copes with each combination - the 16 short subs in your original description.   You should indicate why you believe this won't work.


    I agree that overloading is what I need. But the VB compiler won't allow me to overload objects unless I can tell it at compile time the exact type. Here's some code

    Public Class MainForm
    
      Dim S1 As New Sub1
      Dim S2 As New Sub2
      Dim S3 As New Sub3
    
      Dim SubClassArray() As BaseType = {S1, S2, S3}
    
       Friend Sub DoTest()
    
        Dim s, s1 As BaseType
    
        For Each s In SubClassArray
          For Each s1 In SubClassArray
            BaseType.DoIt(s, s1)  '******** This does not compile ******
          Next
        Next
    
      End Sub
    
    End Class
    
    Friend MustInherit Class BaseType
    
      Friend Shared Sub DoIt(P1 As Sub1, P2 As Sub1)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub1, P2 As Sub2)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub1, P2 As Sub3)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub2, P2 As Sub1)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub2, P2 As Sub2)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub2, P2 As Sub3)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub3, P2 As Sub1)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub3, P2 As Sub2)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub3, P2 As Sub3)
    
      End Sub
    
    End Class
    
    Friend Class Sub1
      Inherits BaseType
    
    End Class
    
    Friend Class Sub2
      Inherits BaseType
    
    End Class
    
    Friend Class Sub3
      Inherits BaseType
    
    End Class
    
    
    

    Put that into the IDE and you get an error on the line I've commented. I can't cut and paste the error, but it says that the only methods available need a narrowing conversion which is illegal.

    It doesn't matter if I make DoIt shared or not, you get the same result.

    I need the inheritance (as  much as anyone does - spaghetti is always an option - this all came about because I was trying to clean up my code a bit) to distinguish between the available properties of the individual objects. And the overloading for reasons that I think we both agree on.


    Peter

    Thursday, December 07, 2017 4:04 PM
  • I agree that overloading is what I need. But the VB compiler won't allow me to overload objects unless I can tell it at compile time the exact type. Here's some code

    Overloading is based on a signature. That signature is made of the difference of the types (classes) passed in it. 

    Some don't understand why the drawing class has so many ways with different types which seems a little bit to do the same. But that is not the case. More (overloaded) methods are created by using different types which seems to do nothing.

    Therefore asking to create overload methods with the Class Object alone is silly. 

    Not that I think you read my messages. Therefore for those who find this thread. 


    Success
    Cor







    Thursday, December 07, 2017 5:07 PM
  • Overloading is based on a signature. That signature is made of the difference of the types (classes) passed in it. 

    Some don't understand why the drawing class has so many ways with different types which seems a little bit to do the same. But that is not the case. More (overloaded) methods are created by using different types which seems to do nothing.

    Therefore asking to create overload methods with the Class Object alone is silly. 

    Not that I think you read my messages. Therefore for those who find this thread. 


    Success
    Cor

    Cor,

    I do read your threads, as well as everyone else's. I  find them very hard to understand. You talk about "some don't understand" - I understand what a signature is - it's not that hard. I don't have a "drawing" class, either in my analogy or in my code, so it's not easy to work out what you are talking about. I think you must be so clever that you do not understand how people, even those with decades of experience in programming like myself, think. I also think that you do not read my answers!


    Peter

    Thursday, December 07, 2017 7:11 PM
  • Overloading is based on a signature. That signature is made of the difference of the types (classes) passed in it. 

    Some don't understand why the drawing class has so many ways with different types which seems a little bit to do the same. But that is not the case. More (overloaded) methods are created by using different types which seems to do nothing.

    Therefore asking to create overload methods with the Class Object alone is silly. 

    Not that I think you read my messages. Therefore for those who find this thread. 


    Success
    Cor

    Cor,

    I do read your threads, as well as everyone else's. I  find them very hard to understand. You talk about "some don't understand" - I understand what a signature is - it's not that hard. I don't have a "drawing" class, either in my analogy or in my code, so it's not easy to work out what you are talking about. I think you must be so clever that you do not understand how people, even those with decades of experience in programming like myself, think. I also think that you do not read my answers!


    Peter

    Peter, 

    You're probably longer active then I. I started with punching cards on this kind of machines. 

    Like everybody else I had of course fellow workers, they told the punchcard would never go away. Yea likewise with what you write in this thread constantly. I did not agree with them, likewise the punchcard I lost them out of my eye. 

    It is a same kind of writing you do. You are right I did not understand those fellow workers. I invested time to teach me new things, not once and told it was like that forever, but changed what I did again and again and again. Sometimes it took time. Most of the time because things were described in books, where I currently know one page is enough. But you cannot sell books of one page of course.

    The concept you seems try to follow I've seen endless persons trying. The trouble I (and not me alone) with it have is that it goes with small projects, but as soon as projects become real time solutions they go out of the scope of those who are working on them. 

    However, you have of course a much longer experience than me. 


    Success
    Cor



    Thursday, December 07, 2017 7:32 PM
  • I agree that overloading is what I need. But the VB compiler won't allow me to overload objects unless I can tell it at compile time the exact type. Here's some code

      Dim SubClassArray() As BaseType = {S1, S2, S3}
    
       Friend Sub DoTest()
    
        Dim s, s1 As BaseType
    
        For Each s In SubClassArray
          For Each s1 In SubClassArray   
    

    S and S1 are variables of Type BaseType, and you haven't provided an overload for that. 

    You need to sort out how you are actually creating and handling the Triangle, Circle, Square etc objects before worrying about how to call the function to do the intersection.  Are you going to pass the objects in variables of the base type (BaseType) when you call the function or are you going to pass the objects in variables of the derived type (Triangle, Circle, Square etc) when you call the function?   That's the 'context' issue I described above. 

    If you call the function with variables of the derived type then overloading is the way to go.  If you call the function with variables of the base type then there is only one function, and that function has to work out how to handle the objects that were passed.

    Your code above is a mixture, and won't work.  


    • Edited by AcamarMVP Thursday, December 07, 2017 8:43 PM sp
    • Marked as answer by ptoye Saturday, December 09, 2017 3:38 PM
    • Unmarked as answer by ptoye Saturday, December 09, 2017 3:50 PM
    • Marked as answer by ptoye Saturday, December 09, 2017 3:50 PM
    Thursday, December 07, 2017 8:42 PM

  • You're probably longer active then I. I started with punching cards on this kind of machines. 


    That brings back memories! Although most of my earlier life was spent with paper tape rather than cards. More difficult to edit, but slightly less disastrous when dropped. But that was in the 1960s and 70s. Most of the time I was working in assembler code, wihch was all that was available for systems programming in those days. Which is why I'm struggling a bit with OO programming, which started up after I stopped writing programs and took up network consultancy instead.


    Peter

    Saturday, December 09, 2017 3:30 PM
  • You need to sort out how you are actually creating and handling the Triangle, Circle, Square etc objects before worrying about how to call the function to do the intersection.  Are you going to pass the objects in variables of the base type (BaseType) when you call the function or are you going to pass the objects in variables of the derived type (Triangle, Circle, Square etc) when you call the function?   That's the 'context' issue I described above. 

    If you call the function with variables of the derived type then overloading is the way to go.  If you call the function with variables of the base type then there is only one function, and that function has to work out how to handle the objects that were passed.

    Your code above is a mixture, and won't work.  


    Aha! Light is dawning. I had assumed that the system would work out at runtime what the exact object type was and call the correct subroutine. And. as you and others have pointed out, it won't.

    It looks as if I will have to do it some other way, probably by having a variable which is set to a different constant (probably an enum value) for each type, followed by a load of Select Case statements, which will be far more efficient than using TypeOf or GetType (which I assume compile to similar code).

    Sorry it's taken me so long to get here, and many thank to you and the others who have helped me.


    Peter

    Saturday, December 09, 2017 3:56 PM
  •   ...and many thank to you and the others who have helped me.

    Peter

    If others have helped then at the very least, please up-vote those others.

    We're all just volunteers here -- nobody in this thread is being paid to help answer your question, so the little payment we request is to spend a few minutes and give credit with up-voting.


    "A problem well stated is a problem half solved.” - Charles F. Kettering


    • Edited by Frank L. Smith Saturday, December 09, 2017 4:01 PM ...typo
    Saturday, December 09, 2017 4:01 PM
  • That brings back memories! Although most of my earlier life was spent with paper tape rather than cards. More difficult to edit, but slightly less disastrous when dropped. But that was in the 1960s and 70s. Most of the time I was working in assembler code, wihch was all that was available for systems programming in those days. Which is why I'm struggling a bit with OO programming, which started up after I stopped writing programs and took up network consultancy instead.


    Peter

    If you really are a programmer of those days (not that I doubt about that), you know that memory was always very expensive to use. 

    So what did you do, as soon as something was not necessary anymore, you did put something new on that place. 

    With OOP happens the same in a kind of stack mechanism (let things go out of scoop). But what is more sufficient than to use pre created types on those places (which are named classes) instead that you are building again and again in memory from its base object. Be aware that OOP is not the same as OO.

    In fact very simple. 

    Around this is of course more optimized but in fact this is one of the bases for OOP and one of that what is used is the OO way of class (type) description. 


    Success
    Cor





    Saturday, December 09, 2017 4:09 PM
  • If you really are a programmer of those days (not that I doubt about that), you know that memory was always very expensive to use. 

    So what did you do, as soon as something was not necessary anymore, you did put something new on that place. 

    With OOP happens the same in a kind of stack mechanism (let things go out of scoop). But what is more sufficient than to use pre created types on those places (which are named classes) instead that you are building again and again in memory from its base object. Be aware that OOP is not the same as OO.

    In fact very simple. 

    Around this is of course more optimized but in fact this is one of the bases for OOP and one of that what is used is the OO way of class (type) description. 


    Success
    Cor


    Yes, I remember when RAM cost 1 1/2 US cents per bit. We would have programming competitions to try to fit an algorithm into the minimum of storage. And how much is memory now? USB sticks at about 25 cents per Gigabit.

    I don't understand your point that OO is not the same as OOP. OO is short for "object-oriented" and the "P" just adds "programming". Are you trying to say that the implementation is not equivalent to the design? We're about to get into philosophy and word-chopping here.


    Peter

    Saturday, December 09, 2017 6:50 PM
  • @ptoye - not clear what you are doing, but Generics might help.  A short example.



    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it" - MSDN User JohnWein

    As I understand generics, there aren't any in this code, just the use of TypeOf to determine the run-time type of the object. I'd already mentioned that in my original query, and I've found that this is very inefficient so have discarded it. The original question was whether I've missed something obvious in trying to use late binding to sort out the types without complex Select Case statements. It seems that it isn't!

    I'm interested in your quote from John Wein but I can't locate it.Where did you get it from?


    Peter

    Saturday, December 09, 2017 7:00 PM
  • I'd not considered Interfaces. I'll read up on them. Thanks.

    Peter

    As a working example, have a look at the following then I'll explain what I meant about a "HasA" inheritance type:

    The function only knows that "by contract" whatever class it is has agreed to implement the two read-only properties of that interface.

    Food for thought. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thanks Frank - that must have taken some time to put together. In other situations it might well have worked, but if you look at my "Shape" idea (which of course I posted after the above) you'll see that it's the methods that have to change for each type (hence my wish to overload) rather than the properties. So I can't see that it would help me. I'll mark it as an answer, though, because it answers a slightly different question and might be useful to someone else.

    Peter

    Saturday, December 09, 2017 7:06 PM
  • In modern VB, if late binding is enabled (i.e. Option Strict Off), at least for the file that contains DoIt, then try this:

     

       Sub DoIt(A As BaseType, B As BaseType)

     

          Dim oA As Object = A

          Dim oB As Object = B

     

          ShortSub(oA, oB)

     

       End Sub

     

    Assuming that there are a series of ShortSub routines having the corresponding parameter types Type1, Type2, etc.

    The above single call will perform something similar to your Ifs.




    I don't think this works - see my post on 7th at 4:04 pm. Or have I misunderstood something as usual?

    Peter

    Saturday, December 09, 2017 7:12 PM

  • So I can't see that it would help me. I'll mark it as an answer, though, because it answers a slightly different question and might be useful to someone else.

    Peter

    If it doesn't answer your question then please un-mark me as being an answerer.

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, December 09, 2017 7:15 PM
  • In modern VB, if late binding is enabled (i.e. Option Strict Off), at least for the file that contains DoIt, then try this:

     

       Sub DoIt(A As BaseType, B As BaseType)

     

          Dim oA As Object = A

          Dim oB As Object = B

     

          ShortSub(oA, oB)

     

       End Sub

     

    Assuming that there are a series of ShortSub routines having the corresponding parameter types Type1, Type2, etc.

    The above single call will perform something similar to your Ifs.




    I don't think this works - see my post on 7th at 4:04 pm. Or have I misunderstood something as usual?

    Peter


    You probably did not try it yet. The late binding must be enabled, DoIt subs must be accessible (e.g. public) and the loop will be:

       For Each s In SubClassArray

          For Each s1 In SubClassArray

             Dim a As Object = s

             Dim b As Object = s1

             BaseType.DoIt(a, b)

          Next

       Next


    • Edited by Viorel_MVP Saturday, December 09, 2017 7:23 PM
    • Marked as answer by ptoye Tuesday, December 12, 2017 12:00 PM
    Saturday, December 09, 2017 7:23 PM
  • In modern VB, if late binding is enabled (i.e. Option Strict Off), at least for the file that contains DoIt, then try this:

     

       Sub DoIt(A As BaseType, B As BaseType)

     

          Dim oA As Object = A

          Dim oB As Object = B

     

          ShortSub(oA, oB)

     

       End Sub

     

    Assuming that there are a series of ShortSub routines having the corresponding parameter types Type1, Type2, etc.

    The above single call will perform something similar to your Ifs.




    I don't think this works - see my post on 7th at 4:04 pm. Or have I misunderstood something as usual?

    Peter


    You probably did not try it yet. The late binding must be enabled, DoIt subs must be accessible (e.g. public) and the loop will be:

       For Each s In SubClassArray

          For Each s1 In SubClassArray

             Dim a As Object = s

             Dim b As Object = s1

             BaseType.DoIt(a, b)

          Next

       Next


    Sorry this is going to be a long message.

    I did try it, and the code compiles OK, but I get a run-time error:

    System.MissingMemberException occurred
      HResult=0x80131512
      Message=Public member 'DoIt' on type 'BaseType' not found.
      Source=Microsoft.VisualBasic
      StackTrace:
       at Microsoft.VisualBasic.CompilerServices.Symbols.Container.GetMembers(String& MemberName, Boolean ReportErrors)
       at Microsoft.VisualBasic.CompilerServices.NewLateBinding.CallMethod(Container BaseReference, String MethodName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack, BindingFlags InvocationFlags, Boolean ReportErrors, ResolutionFailure& Failure)
       at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateCall(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack, Boolean IgnoreReturn)
       at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCall(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack, Boolean IgnoreReturn)
       at TestOverload.BaseType.Doit1(BaseType A, BaseType B) in D:\Peter\VB\TestOverload\TestOverload\MainForm.vb:line 51
       at TestOverload.MainForm.DoTest() in D:\Peter\VB\TestOverload\TestOverload\MainForm.vb:line 30
       at TestOverload.MainForm..ctor() in D:\Peter\VB\TestOverload\TestOverload\MainForm.vb:line 20

    The code is the first block below - try it. But I have found a way which is slightly long-winded, but uses the inheritance mechanism to get the spaghetti out of the BaseClass and into the subclasses. That's the second block below.

    Imports System.Text
    
    Public Class MainForm
    
      Dim S1 As Sub1
      Dim S2 As Sub2
    
      Dim SubClassArray(1) As BaseType
      Friend SB As StringBuilder
    
      Sub New()
    
        ' This call is required by the designer.
        InitializeComponent()
        SB = New StringBuilder
        S1 = New Sub1(Me)
        S2 = New Sub2(Me)
        SubClassArray(0) = S1
        SubClassArray(1) = S2
        DoTest()
    
      End Sub
    
      Friend Sub DoTest()
    
        Dim s, s1 As BaseType
    
        For Each s In SubClassArray
          For Each s1 In SubClassArray
            BaseType.Doit1(s, s1)
          Next
        Next
        boxOutput.Text = SB.ToString
    
      End Sub
    
    End Class
    
    Friend MustInherit Class BaseType
    
      Friend Shared F As MainForm
    
      Public Sub New(MF As MainForm)
        F = MF
      End Sub
    
      Friend Shared Sub Doit1(A As BaseType, B As BaseType)
    
        Dim oA As Object = A
        Dim oB As Object = B
        DoIt(oA, oB)
    
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub1, P2 As Sub1)
        F.SB.Append("Sub1, Sub1")
        F.SB.AppendLine()
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub1, P2 As Sub2)
        F.SB.Append("Sub1, Sub2")
        F.SB.AppendLine()
      End Sub
    
    
      Friend Shared Sub DoIt(P1 As Sub2, P2 As Sub1)
        F.SB.Append("Sub2, Sub1")
        F.SB.AppendLine()
      End Sub
    
      Friend Shared Sub DoIt(P1 As Sub2, P2 As Sub2)
        F.SB.Append("Sub2, Sub2")
        F.SB.AppendLine()
      End Sub
    
    End Class
    
    Friend Class Sub1
      Inherits BaseType
    
      Public Sub New(MF As MainForm)
        MyBase.New(MF)
      End Sub
    
    End Class
    
    Friend Class Sub2
      Inherits BaseType
    
      Public Sub New(MF As MainForm)
        MyBase.New(MF)
      End Sub
    
    End Class
    

    My solution:

    Imports System.Text
    
    Public Class MainForm
    
      Dim S1 As Sub1
      Dim S2 As Sub2
    
      Dim SubClassArray(1) As BaseType
      Friend SB As StringBuilder
    
      Sub New()
    
        ' This call is required by the designer.
        InitializeComponent()
        SB = New StringBuilder
        S1 = New Sub1(Me)
        S2 = New Sub2(Me)
        SubClassArray(0) = S1
        SubClassArray(1) = S2
        DoTest()
    
      End Sub
    
      Friend Sub DoTest()
    
        Dim s, s1 As BaseType
    
        For Each s In SubClassArray
          For Each s1 In SubClassArray
            s.Doit2(s1)
          Next
        Next
        boxOutput.Text = SB.ToString
    
      End Sub
    
    End Class
    
    Friend MustInherit Class BaseType
    
      Friend F As MainForm
    
      Public Sub New(MF As MainForm)
        F = MF
      End Sub
    
      Friend MustOverride Sub Doit2(BT As BaseType)
      Friend MustOverride Sub DoIt2WithSub1(B As BaseType)
      Friend MustOverride Sub DoIt2WithSub2(B As BaseType)
    
    End Class
    
    Friend Class Sub1
      Inherits BaseType
    
      Public Sub New(MF As MainForm)
        MyBase.New(MF)
      End Sub
    
      Friend Overrides Sub DoIt2(B As BaseType)
        B.DoIt2WithSub1(Me)
      End Sub
    
      Friend Overrides Sub DoIt2WithSub1(B As BaseType)
        F.SB.Append("Sub1, Sub1")
        F.SB.AppendLine()
      End Sub
    
      Friend Overrides Sub DoIt2WithSub2(B As BaseType)
        F.SB.Append("Sub2, Sub1")
        F.SB.AppendLine()
      End Sub
    
    End Class
    
    Friend Class Sub2
      Inherits BaseType
    
      Public Sub New(MF As MainForm)
        MyBase.New(MF)
      End Sub
    
      Friend Overrides Sub DoIt2(B As BaseType)
        B.DoIt2WithSub2(Me)
      End Sub
    
      Friend Overrides Sub DoIt2WithSub1(B As BaseType)
        F.SB.Append("Sub1, Sub2")
        F.SB.AppendLine()
      End Sub
    
      Friend Overrides Sub DoIt2WithSub2(B As BaseType)
        F.SB.Append("Sub2, Sub2")
        F.SB.AppendLine()
      End Sub
    
    End Class
    
    


    Peter

    Monday, December 11, 2017 11:16 AM
  • In order to avoid the “Public member 'DoIt' on type 'BaseType' not found” error, try Public instead of Friend for all of DoIt.

    Monday, December 11, 2017 4:03 PM
  • In order to avoid the “Public member 'DoIt' on type 'BaseType' not found” error, try Public instead of Friend for all of DoIt.

    Interesting - it now works. Thanks very much.

    But I can't work out why it works any differently with "public" instead of "friend". Reading the VB.Net documentation, it states : "Specifies that one or more declared programming elements are accessible only from within the assembly that contains their declaration."  And all of the elements are within the same assembly - even the same file! Any ideas why?


    Peter

    Monday, December 11, 2017 7:26 PM
  • According to Language Specification (“Late-Bound Expressions” section), the non-public members are ignored when doing late-binding. Unfortunately, it is not explained why. Seems a limitation of VB.NET. (By the way, in C# such dynamic invocation is not restricted).

    • Marked as answer by ptoye Tuesday, December 12, 2017 12:00 PM
    Monday, December 11, 2017 8:44 PM
  • According to Language Specification (“Late-Bound Expressions” section), the non-public members are ignored when doing late-binding. Unfortunately, it is not explained why. Seems a limitation of VB.NET. (By the way, in C# such dynamic invocation is not restricted).

    Viorel,

    Option Strict Off is not totally the same as Dynamic in C#. Option Strict off has also some "features" to make easier VB6 behaviour possible. 


    Success
    Cor

    Tuesday, December 12, 2017 4:31 AM
  • According to Language Specification (“Late-Bound Expressions” section), the non-public members are ignored when doing late-binding. Unfortunately, it is not explained why. Seems a limitation of VB.NET. (By the way, in C# such dynamic invocation is not restricted).


    Thanks Viorel. It seems a bit odd, but as I said above, hey, that's language design. I'll get back to the project now.

    Peter

    Tuesday, December 12, 2017 12:00 PM
  • As a coda to all of this I wrote a program which did a time trial of the two solutions, and found two things which may be of interest:

    1) My solution which uses overriding and two levels of subroutine call is very much more efficient than Viorel's solution, which I imagine uses reflection (albeit hidden).

    2) Microsoft have screwed up in the latest releases of Visual Studio, and setting Option Strict on within the project properties has stopped working :( Unfortunately another bug means that I have to use version 15 :((

    VB, option Strict On warnings are shown on existing project.

    Reported by Dmitri Peredera 12/5/2017, 7:38:53 AM
    Fixed - Pending ReleaseWindows 10.0Visual Studio 2017 version 15.5
    Strict On is not set anywhere and warnings are shown.


    Peter

    16 hours 29 minutes ago