From: ekkehard.horner on
Peter Olcott schrieb:
> On 8/6/2010 7:07 PM, Mayayana wrote:
>> I don't know if you can actually create an array
>> of objects. It sounds like what you want is
>> a Dictionary. But if you want an object hierarchy
>> it might be better to use classes.
>>
>> | Can a Component written in VBScript return an array of different Object
>> | types? In other words the elements of the array are not the same type.
>> |
>>
>>
> How would a dictionary of COM components work in VBScript?
>
As
I told
Tom showed
I will prove to
you, there are no problems whatsoever to store different (types of)
objects in VBScript arrays. Mayayana's speculations are just that.

This is a bare bone .wsc:

<?xml version="1.0"?>
<component>
<registration
description="Quak"
progid="Quak.WSC"
version="1.00"
classid="{d0ccb637-bd0c-4c90-a4bd-7473f499d35a}">
</registration>
<public>
<method name="getWhatever" />
</public>
<script language="VBScript">
<![CDATA[

' OO - Inheritance = Repeat Yourself
' (Here I *want* distinct classes, but in VBScript I *can't* have a
hierarchy)
Class cDuck : Function speak() : speak = "Duck: quak" : End Function
: End Class
Class cParrot : Function speak() : speak = "Parrot: quak" : End Function
: End Class
Class cFrog : Function speak() : speak = "Frog: quak" : End Function
: End Class

Function getWhatever()
getWhatever = Array( _
New cDuck _
, New cParrot _
, New cFrog _
)
End Function

]]>
</script>
</component>

and this .wsf shows how scripting languages with tolerant type
systems can use the VBScript array:

<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
<package>
<job id="testquak">
<?job error="true" debug="true" ?>

<script language="Python">
<![CDATA[
#
############################################################################

import win32com.client

def PYQuak():
oQuak = win32com.client.Dispatch( "Quak.WSC" )
aWhatever = oQuak.getWhatever()
for oWhatever in aWhatever:
print oWhatever.speak()

#
############################################################################
]]>
</script>

<script language="Perlscript">
<![CDATA[
#
############################################################################

use strict;
use warnings;
use Win32::OLE;

sub PLQuak {
my $oQuak = Win32::OLE->new( 'Quak.WSC' );
my @aWhatever = @{$oQuak->getWhatever()};
foreach (@aWhatever) {
print $_->speak(), "\n";
}
}

#
############################################################################
]]>
</script>

<script language="JScript">
<![CDATA[
//
###########################################################################

function JSQuak() {;
var oQuak = new ActiveXObject( "Quak.WSC" );
var aWhatever = new VBArray( oQuak.getWhatever() ).toArray();
for (var i = 0; i < aWhatever.length; ++i) {
WScript.Echo( aWhatever[ i ].speak() );
}
}

//
###########################################################################
]]>
</script>

<script language="VBScript">
<![CDATA[
'
############################################################################

Option Explicit

''# MAIN
'
############################################################################
WScript.Quit doMain()

''= doMain() -
'
============================================================================
Function doMain()
doMain = 1

WScript.Echo "----------- VBScript -----------"

Dim oQuak : Set oQuak = CreateObject( "Quak.WSC" )
Dim aWhatever : aWhatever = oQuak.getWhatever()
Dim oWhatever
For Each oWhatever In aWhatever
WScript.Echo oWhatever.Speak()
Next

WScript.Echo "----------- JScript -----------"
JSQuak

WScript.Echo "----------- Perl -----------"
PLQuak

WScript.Echo "----------- Python -----------"
PYQuak

doMain = 0
End Function

'
############################################################################
]]>
</script>
</job>
</package>

output:

cscript //D testquak.wsf
----------- VBScript -----------
Duck: quak
Parrot: quak
Frog: quak
----------- JScript -----------
Duck: quak
Parrot: quak
Frog: quak
----------- Perl -----------
Duck: quak
Parrot: quak
Frog: quak
----------- Python -----------
Duck: quak
Parrot: quak
Frog: quak

As you can see, there may be special efforts involved to make the
VBScript array accessible:

(JScript)
var oQuak = new ActiveXObject( "Quak.WSC" );
var aWhatever = new VBArray( oQuak.getWhatever() ).toArray();

I wouldn't be sure that such features exist in every language that
claims to be able to use COM objects.

Scripting languages tend to be tolerant wrt types (late binding);
they will try to invoke methods on an object trusting the programmer.

Compiled languages like the members of the .NET family rely on
type information (early binding). You probably can tell a C# or
VB.NET program the the thingy you get back from oQuak.getWhatever()
is an array of Objects, but I doubt that a strictly typed language
will let you call .speak() on something it knows only as an Object.

Have a look at

http://www.dotnet247.com/247reference/msgs/31/156831.aspx

to see a discussion about .WSC and .NET.

Perhaps you can use Reflection and Invoke as a workaround or the
new Dynamic Typing of .NET 4.0, but I wouldn't start investing
work in VBScript components without *proof* that it really works
in the languages to be (claimed as) supported.
From: Mayayana on
| there are no problems whatsoever to store different (types of)
| objects in VBScript arrays. Mayayana's speculations are just that.

Yes, I see that you're right:

Dim A1(3), i, s
A1(0) = "eee"
A1(1) = 3
A1(2) = Array(1, 2, 3)
Set A1(3) = CreateObject("Shell.Application")

For i = 0 to 3
s = s & typename(A1(i)) & vbCrLf
Next
MsgBox s
Set A1(3) = Nothing

I'm used to VB, where arrays work the same
way but are normally strongly typed. Personally,
though, I think I'd still use a Dictionary to
reference a variety of objects.


From: ekkehard.horner on
Mayayana schrieb:
> | there are no problems whatsoever to store different (types of)
> | objects in VBScript arrays. Mayayana's speculations are just that.
>
> Yes, I see that you're right:
>
> Dim A1(3), i, s
> A1(0) = "eee"
> A1(1) = 3
> A1(2) = Array(1, 2, 3)
> Set A1(3) = CreateObject("Shell.Application")
>
> For i = 0 to 3
> s = s& typename(A1(i))& vbCrLf
> Next
> MsgBox s
> Set A1(3) = Nothing
>
> I'm used to VB, where arrays work the same
> way but are normally strongly typed. Personally,
> though, I think I'd still use a Dictionary to
> reference a variety of objects.
>
>
It goes without saying that you may do whatever you like, but in
my opinion there is no reason to use a dictionary if you want to
store different kinds of objects in a collection.

What colection you choose should not be determined by the nature
of the elements you want to store but by the services/features of
the collection you need. Nothing in the OT's postings indicates
that he needs to access the elements 'by name' (as oposed to 'by
number/index').

If the shortcomings of the VBScript array (the need to copy when
growing the array or when changing elements in nested arrays)
become a problem, switching to the .NET Arraylist may be a way
out.

From: Mayayana on
| What colection you choose should not be determined by the nature
| of the elements you want to store but by the services/features of
| the collection you need. Nothing in the OT's postings indicates
| that he needs to access the elements 'by name' (as oposed to 'by
| number/index').
|

Does it really make sense to you to access
a number of disparate objects by remembering
their numeric offset in an array? As you've
shown, it can be done. The next question is "why?".

I don't use a Dictionary often, but I do find
them very useful. And the author of O'Reilly's
VB book says they're actually notably faster
than a Collection.

In any case, I appreciate your generosity of
spirit in allowing me to do things the wrong way. :)

But it seems that the real point was never
addressed here: Peter Olcott never described
what he's actually trying to do. And storing
object references is not a good idea in the
first place. (As an example, I once wrote code
that stored references to the IE objects representing
all open folders. On Win98, if a folder was closed
before the object was released, Explorer would crash.)

So we're really just discussing the variety of
data types.



From: ekkehard.horner on
Mayayana schrieb:
> | What colection you choose should not be determined by the nature
> | of the elements you want to store but by the services/features of
> | the collection you need. Nothing in the OT's postings indicates
> | that he needs to access the elements 'by name' (as oposed to 'by
> | number/index').
> |
>
> Does it really make sense to you to access
> a number of disparate objects by remembering
> their numeric offset in an array? As you've
> shown, it can be done. The next question is "why?".
>
Yes, it makes sense to me to access the elements of a collection
by number/index, because I don't need to equate "accessing by
index" with "remembering the index".

> I don't use a Dictionary often, but I do find
> them very useful. And the author of O'Reilly's
> VB book says they're actually notably faster
> than a Collection.
>
I use dictionaries often - when it makes sense to do so. For
example, if you want to determine the frequencies of words
in a text, it's convenient to use the words as keys and the
counts as values in a dictionary.

dicFreq( CurrentWord ) = dicFreq( CurrentWord ) + 1

beats using a function that loops over the first column of a
two-dimensional array to find (or append) the CurrentWord and
update the corresponding cell in the second columns every time.
(BTW: in both cases there is no need for the programmer to remember
the 'names' or the indices of the items)

I doubt that an author of an O'Reilly book would get away with
stating that a dictionary is "faster than a Collection", as this
is like saying that a Prius is faster than a car. (Nevertheless,
I'd like to get a usable reference.)

For people interested in the efficieny of most basic operations
on arrays and dictionaries:

Dim nUB : nUB = 333333
WScript.Echo nUB, "elms Array vs. Dictionary"
cudDic nUB
cudArray nUB

Sub cudArray( nUB )
Dim nTime
nTime = Timer()
ReDim aX( nUB )
WScript.Echo "ReDim:", FormatNumber( Timer() - nTime, 6 )

nTime = Timer()
Dim nIdx
For nIdx = 0 To nUB
aX( nIdx ) = nIdx
Next
WScript.Echo "Fill: ", FormatNumber( Timer() - nTime, 6 )

nTime = Timer()
For nIdx = 0 To nUB
aX( nIdx ) = aX( nIdx ) + 1
Next
WScript.Echo "Upd: ", FormatNumber( Timer() - nTime, 6 )

End Sub

Sub cudDic( nUB )
Dim nTime
nTime = Timer()
Dim dicX : Set dicX = CreateObject( "Scripting.Dictionary" )
WScript.Echo "Creat:", FormatNumber( Timer() - nTime, 6 )

nTime = Timer()
Dim nIdx
For nIdx = 0 To nUB
dicX( nIdx ) = nIdx
Next
WScript.Echo "Fill: ", FormatNumber( Timer() - nTime, 6 )

nTime = Timer()
For nIdx = 0 To nUB
dicX( nIdx ) = dicX( nIdx ) + 1
Next
WScript.Echo "Upd: ", FormatNumber( Timer() - nTime, 6 )

End Sub

output:

333333 elms Array vs. Dictionary
Creat: 0.000000
Fill: 3.222656
Upd: 6.839844
ReDim: 0.027344
Fill: 0.101563
Upd: 0.207031

> In any case, I appreciate your generosity of
> spirit in allowing me to do things the wrong way. :)
>

All I hope for is to make people think twice before
they base important decisions on your assumptions.

> But it seems that the real point was never
> addressed here: Peter Olcott never described
> what he's actually trying to do. And storing
> object references is not a good idea in the
> first place. (As an example, I once wrote code
> that stored references to the IE objects representing
> all open folders. On Win98, if a folder was closed
> before the object was released, Explorer would crash.)
>

Rephrased as "be careful not to use your references when
the refered to objects are dead" - agreed.

> So we're really just discussing the variety of
> data types.
>
>
>