[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.vb.general.discussion

VB6 Can I specify a specific 'field' in a UDT?

(Mike Mitchell)

7/31/2011 7:27:00 PM

Let's suppose I have a Sort procedure and I pass it a UDT, such as:

Type MyType
Dog As String
Cat As String
End Type

Public Pets() as MyType

Redim... as required...

Call the Sort proc:

QuickSort Pets(), lo, hi, "Dog"

This will tell the Sort proc to do the comparions using the Dog field.
Alternatively, QuickSort Pets(), lo, hi, "Cat" would target the Cat
field.

Possible?

If not a named field, then what about passing a number, e.g. 1 or 2:
QuickSort Pets(), lo, hi, 1

or

QuickSort Pets(), lo, hi, 2

where 1 signifies Dog and 2 signifies Cat for the comparisons.

MM
10 Answers

ralph

7/31/2011 8:50:00 PM

0

On Sun, 31 Jul 2011 20:26:41 +0100, MM <kylix_is@yahoo.co.uk> wrote:

>Let's suppose I have a Sort procedure and I pass it a UDT, such as:
>
>Type MyType
> Dog As String
> Cat As String
>End Type
>
>Public Pets() as MyType
>
>Redim... as required...
>
>Call the Sort proc:
>
>QuickSort Pets(), lo, hi, "Dog"
>
>This will tell the Sort proc to do the comparions using the Dog field.
>Alternatively, QuickSort Pets(), lo, hi, "Cat" would target the Cat
>field.
>
>Possible?
>
>If not a named field, then what about passing a number, e.g. 1 or 2:
>QuickSort Pets(), lo, hi, 1
>
>or
>
>QuickSort Pets(), lo, hi, 2
>
>where 1 signifies Dog and 2 signifies Cat for the comparisons.
>
>MM

My first reaction whenever I see something like this is, "Why?".
Perhaps an attempt to avoid 'duplicate' code?

My guess is you are trying to overload (make generic) the QuickSort
function through Parameter Polymorphism which will lead to you to a
conditional inside QuickSort in order to specialize the specific
operation to employ - in other words at some point you are going
'branch' into duplicate code anyway.

Also this shows a definite data-centric pattern. You design leads to
the 'client' being far too tightly coupled to the 'store'. Any changes
requires navigating through a lot of code.

The code that performs a specific sort is usually quite short, and
could be duplicate for each element with minimum impact. (also we
don't what your sort code looks like but there is likely an
opportunity to make some key parts generic.)

Wrap your UDT in a Pet object (CPet) then provide two methods:
oPets.SortCats lo, hi
oPets.SortDogs lo, hi

-ralph

Tom Shelton

7/31/2011 10:21:00 PM

0

MM explained on 7/31/2011 :
> Let's suppose I have a Sort procedure and I pass it a UDT, such as:
>
> Type MyType
> Dog As String
> Cat As String
> End Type
>
> Public Pets() as MyType
>
> Redim... as required...
>
> Call the Sort proc:
>
> QuickSort Pets(), lo, hi, "Dog"
>
> This will tell the Sort proc to do the comparions using the Dog field.
> Alternatively, QuickSort Pets(), lo, hi, "Cat" would target the Cat
> field.
>
> Possible?
>
> If not a named field, then what about passing a number, e.g. 1 or 2:
> QuickSort Pets(), lo, hi, 1
>
> or
>
> QuickSort Pets(), lo, hi, 2
>
> where 1 signifies Dog and 2 signifies Cat for the comparisons.
>
> MM

The real issue is the compare routine. Most modern languages would let
you basically pass in the equivalent of a funciton pointer to use as
the comparison (usually, this function would return a -1, 0, 1). In
vb, you could do something similar - using api's etc, but an easier way
would be to use an object for your type and interfaces (well, you can
use a udt, if you define it in a public class module - but for this
example, I'm going to change it to a class). Something like (remember,
this is dummy code - so, it does not reflect best practices):

' CMyType
Public Dog As String
Public Cat As String

That's our type. Now your QuickSort might should change it's last
parameter to be something like IComparer. This interface might look
like:

' IComparer interface.
Public Function Compare(lhs As Object, rhs As Object) As Integer
' no op...
End Function

Now, you could create a comparer for dogs:

' Simple Dog Comparer
Implements IComparer

Private Function IComparer_Compare(lhs As Object, rhs As Object) As
Integer
Dim a As MyType
Dim b As MyType
Set a = lhs
Set b = rhs

Select Case a.Dog
Case Is > b.Dog
IComparer_Compare = 1
Case Is < b.Dog
IComparer_Compare = -1
End Select

End Function

Then, if you want to compare dogs, you can do something like:
Dim dc as IComparer
Set dc = New SimpleDogComparer
QuickSort Pets(), lo, hi, dc

Then you just modify your quicksort routine to sort based on the return
of IComparer.Compare

This way, you keep your quicksort algorithm generic, and decoupled from
any specific type of data. You let the caller define the actual
relative value comparison.

--
Tom Shelton


(Mike Mitchell)

8/1/2011 6:56:00 AM

0

On Sun, 31 Jul 2011 15:49:30 -0500, ralph <nt_consulting64@yahoo.net>
wrote:

>On Sun, 31 Jul 2011 20:26:41 +0100, MM <kylix_is@yahoo.co.uk> wrote:
>
>>Let's suppose I have a Sort procedure and I pass it a UDT, such as:
>>
>>Type MyType
>> Dog As String
>> Cat As String
>>End Type
>>
>>Public Pets() as MyType
>>
>>Redim... as required...
>>
>>Call the Sort proc:
>>
>>QuickSort Pets(), lo, hi, "Dog"
>>
>>This will tell the Sort proc to do the comparions using the Dog field.
>>Alternatively, QuickSort Pets(), lo, hi, "Cat" would target the Cat
>>field.
>>
>>Possible?
>>
>>If not a named field, then what about passing a number, e.g. 1 or 2:
>>QuickSort Pets(), lo, hi, 1
>>
>>or
>>
>>QuickSort Pets(), lo, hi, 2
>>
>>where 1 signifies Dog and 2 signifies Cat for the comparisons.
>>
>>MM
>
>My first reaction whenever I see something like this is, "Why?".
>Perhaps an attempt to avoid 'duplicate' code?

Yes. My example only uses two pets, dog and cat, but in an actual
implementation there could be many more "pets" that need to be
identified in the Sort routine.

[snip]

Let's say the proc starts like this:

Sub QuickSortPets(p_Array() As MyType, ByVal inLow As Long, ByVal inHi
As Long, parm As String)

.....usual routine set-up stuff here....

What I want to avoid is:

Select Case parm
Case "Dog"
While (p_Array(tmpLow).Dog < pivot.Dog And tmpLow < inHi)
tmpLow = tmpLow + 1
Wend
Case "Cat"
While (p_Array(tmpLow).Cat < pivot.Cat And tmpLow < inHi)
tmpLow = tmpLow + 1
Wend
Case "Mouse"
While (p_Array(tmpLow).Mouse < pivot.Mouse tmpLow < inHi)
tmpLow = tmpLow + 1
Wend

.....etc etc for other pets

End Select

Instead, I'd like to write:

Sub QuickSortPets(p_Array() As MyType, ByVal inLow As Long, ByVal inHi
As Long, parm As String)

.....usual routine set-up stuff here....

While (p_Array(tmpLow).parm < pivot.parm And tmpLow < inHi)
tmpLow = tmpLow + 1
Wend

where parm = "Dog" or "Cat"

Ideally, I'd also like to make the Sort routine generic for any UDT,
e.g.

Sub QuickSortPets(p_Array() As AnyType, ByVal inLow As Long, ByVal
inHi As Long, parm As String)

So AnyType could mean any UDT I've written with parm being the
paramter I want to sort on.

However, right now I'm asking only about the parm part. (We can talk
about "AnyType" later!)

MM

Dee Earley

8/1/2011 8:28:00 AM

0

On 31/07/2011 23:21, Tom Shelton wrote:
> In vb, you could do something similar - using api's etc, but an
> easier way would be to use an object for your type and interfaces
> (well, you can use a udt, if you define it in a public class module -
> but for this example, I'm going to change it to a class).

Note that converting to a class also opens up the ability to use
CallByName() to get and set object properties by name.

--
Dee Earley (dee.earley@icode.co.uk)
i-Catcher Development Team
http://www.icode.co.uk...

iCode Systems

(Replies direct to my email address will be ignored.
Please reply to the group.)

Jim Mack

8/1/2011 10:55:00 AM

0

MM wrote:
>
> Ideally, I'd also like to make the Sort routine generic for any UDT,
> e.g.
>
> Sub QuickSortPets(p_Array() As AnyType, ByVal inLow As Long, ByVal
> inHi As Long, parm As String)
>
> So AnyType could mean any UDT I've written with parm being the
> paramter I want to sort on.

Aside from the Class approach, which is the "proper" way to do this --
each field knowing how to sort itself -- you can't do that using pure
VB (unless there are some McKinney tricks I don't know about).

If you want to stick with a procedural approach your sort has to be
external, so that you can write 'MyType() As Any' for the UDT param.

Not an ad, but that's how we do it in Stamina (written in ASM). You
pass in a UDT array of any type and an integer "key array" describing
where the sort field(s) live, what kind they are, and whether they
sort up or down.

So for example you might sort on ascending last name, then descending
age within that, and so on. It's fast and flexible. You could do the
same in C, Delphi, Fortran etc.

--
Jim

Mike Williams

8/1/2011 2:03:00 PM

0

"MM" <kylix_is@yahoo.co.uk> wrote in message
news:t5ic379t79b284qeu0bas27n9hiviaefup@4ax.com...

> Yes. My example only uses two pets, dog and cat, but in
> an actual implementation there could be many more "pets"
> that need to be identified in the Sort routine.

In that case then in addition to what others have said you might like to
consider maintaining a separate Index array of Longs which specify the sort
order of the UDT array. You can then modify your Sort routine so that it
actually sorts the contents of the Index array in accordance with what it
finds in the UDT array, rather than sorting the contents of the UDT array
itself. In this way the Index array specifies the current sort order of the
UDT array whilst the UDT array contents themselves are never moved. If your
UDT has perhaps seven or eight string elements then such a method can be
about ten times faster than sorting the UDT array itself, because there is
very much less movement of data.

Mike



(Mike Mitchell)

8/1/2011 2:11:00 PM

0

On Mon, 1 Aug 2011 06:55:14 -0400, "Jim Mack" <no-uce-ube@mdxi.com>
wrote:

>MM wrote:
>>
>> Ideally, I'd also like to make the Sort routine generic for any UDT,
>> e.g.
>>
>> Sub QuickSortPets(p_Array() As AnyType, ByVal inLow As Long, ByVal
>> inHi As Long, parm As String)
>>
>> So AnyType could mean any UDT I've written with parm being the
>> paramter I want to sort on.
>
>Aside from the Class approach, which is the "proper" way to do this --
>each field knowing how to sort itself -- you can't do that using pure
>VB (unless there are some McKinney tricks I don't know about).
>
>If you want to stick with a procedural approach your sort has to be
>external, so that you can write 'MyType() As Any' for the UDT param.
>
>Not an ad, but that's how we do it in Stamina (written in ASM). You
>pass in a UDT array of any type and an integer "key array" describing
>where the sort field(s) live, what kind they are, and whether they
>sort up or down.

Well, that sounds like what QuickPak Pro did (which I've still got up
to version 4.3), e.g.
Declare Sub SortT Lib "QPROxx.DLL" (ByRef AV As tagAV, ByVal NumEls As
Long, ByVal Direction As Long, ByVal ElSize As Long, ByVal ElOffset
Long, ByVal ElSize As Long)

But I reckon VB6 is plenty fast enough for just a few thousand rows.
The QuickSort routine I got off vbnet.mvps.org certianly is.

MM

Jim Mack

8/1/2011 2:32:00 PM

0

MM wrote:
> Jim Mack wrote:
>>
>> Not an ad, but that's how we do it in Stamina (written in ASM). You
>> pass in a UDT array of any type and an integer "key array"
>> describing where the sort field(s) live, what kind they are, and
>> whether they sort up or down.
>
> Well, that sounds like what QuickPak Pro did (which I've still got
> up to version 4.3), e.g.
> Declare Sub SortT Lib "QPROxx.DLL" (ByRef AV As tagAV, ByVal NumEls
> As Long, ByVal Direction As Long, ByVal ElSize As Long, ByVal
> ElOffset Long, ByVal ElSize As Long)
>
> But I reckon VB6 is plenty fast enough for just a few thousand rows.
> The QuickSort routine I got off vbnet.mvps.org certianly is.

The approaches are similar, but Stamina also allows index sorting. I
don't know exactly what QP is doing, but the fact that you don't pass
in an array very likely means that you can't sort certain UDTs because
of Ansi-aliasing. Stamina uses a typelib to avoid that.

And it isn't a question of speed, but of flexibility. Instead of
writing several sorts customized for each class or UDT, you write
simple 'data declarations' in the form of key arrays.

But whatever. As I said, not an ad, just info.

--
Jim

Jason Keats

8/1/2011 2:49:00 PM

0

MM wrote:
> Let's suppose I have a Sort procedure and I pass it a UDT, such as:
>
> Type MyType
> Dog As String
> Cat As String
> End Type
>
> Public Pets() as MyType
>
> Redim... as required...
>
> Call the Sort proc:
>
> QuickSort Pets(), lo, hi, "Dog"
>
> This will tell the Sort proc to do the comparions using the Dog field.
> Alternatively, QuickSort Pets(), lo, hi, "Cat" would target the Cat
> field.
>
> Possible?
>
> If not a named field, then what about passing a number, e.g. 1 or 2:
> QuickSort Pets(), lo, hi, 1
>
> or
>
> QuickSort Pets(), lo, hi, 2
>
> where 1 signifies Dog and 2 signifies Cat for the comparisons.
>
> MM

It may be possible to do what you want using a reference to "TypeLib
Information" (ie tlbinf32.dll).

I've used it to serialise/deserialise custom classes to XML/JSON and to
copy the contents of recordsets to and from a class (rather than
generating code to do this) - but not to investigate the contents of
UDTs (or sort them).

These links should help if you're interested in looking into it:

http://stackoverflow.com/questions/547903/self-inspection-o...
http://www.devx.com/vb2themax/Article/...
http://msdn.microsoft.com/en-us/magazine/bb9...

HTH

(Mike Mitchell)

8/1/2011 7:03:00 PM

0

On Tue, 02 Aug 2011 00:49:10 +1000, Jason Keats
<jkeats@melbpcDeleteThis.org.au> wrote:

>These links should help if you're interested in looking into it:
>
>http://stackoverflow.com/questions/547903/self-inspection-o...
>http://www.devx.com/vb2themax/Article/...
>http://msdn.microsoft.com/en-us/magazine/bb9...

Especially the first link above (stackoverflow) I found very helpful
and interesting. I've got such a lot to learn about VB classic's
internal workings, I need another lifetime! I'm going to paste all
that code into a test app tomorrow just to see it working.

Thanks.

MM