Wednesday, August 8, 2007

Dynamic LS-methods - Allow fluid number of/types of parameters

The easier / better way, use Lists... :)

Thanks Dwight and Sean.


My example is quite simple, but with some data-type testing/object testing and decent error-handling, I think you could expand this "idea" into more advanced Subs/Functions.

Instead of setting the method to accept a fixed amount of parameters, set it to accept one object. In my example, I use a Class that allows you to add different objects (through a variant-array).

There is (at least) one weakness with this approach. You can't add arrays to the Argument-object, as (from what I've read) an array can't contain another array. If it's a string array, you could implode the array, add a symbol at the front of the string to identify it as an array, and split it in the receiving function.

Screenshots of test-agent:
Dim s As New NotesSession
Dim args As New Arguments

Dim doc As NotesDocument
Set doc = s.CurrentDatabase.CreateDocument
doc.subject = "Some mostly harmless planet"

Call args.add( "Tommy Valand" )
Call argumentsAsObject( args )


Call args.add( doc )
Call argumentsAsObject( args )


Call args.add( "Always pack your towel!" )
Call argumentsAsObject( args )


The Arguments-class
The argumentsAsObject-sub
The test-agent
Code in a text-file

The Arguments class:

'argsdemo scriptlib
Class Arguments
Private counter As Integer
Private args() As Variant

Public Sub add( var As Variant)
Redim Preserve args( counter )
If Isobject ( var ) Then
Set args( counter ) = var
Else
args( counter ) = var
End If

counter = counter + 1
End Sub

Public Function getNth( nth As Integer ) As Variant

If Isobject ( args(nth) ) Then
Set getNth = args(nth)
Else
getNth = args(nth)
End If
End Function

Public Function getAll As Variant
getAll = args
End Function

Public Function length As Integer
length = Ubound( args ) + 1
End Function
End Class


Sub that take one parameter (As Arguments):

'accept an Arguments-object
Sub argumentsAsObject( args As Arguments )
Select Case args.length
Case 1
Msgbox "Name: " + args.getNth(0)

Case 2
Msgbox "Name: " + args.getNth(0) + Chr(13) +_
"Address: " + args.getNth(1).subject(0)

Case Else
Dim strTemp As String
Dim counter As Integer
Forall item In args.getAll
'35 - Product object (I know it's a NotesDocument)
If Datatype( item ) = 35 Then
strTemp = strTemp + "Item at index " +_
Cstr( counter ) + ": doc[" + item.subject(0) + "]" + Chr(13)
Else
strTemp = strTemp + "Item at index " +_
Cstr( counter ) + ": " + item + Chr(13)
End If

counter = counter + 1
End Forall
Msgbox strTemp
End Select
End Sub


Full code for the test-agent:

'options
Option Public
Option Declare
Use "argsdemo"

Sub Initialize
Dim s As New NotesSession
Dim args As New Arguments

Dim doc As NotesDocument
Set doc = s.CurrentDatabase.CreateDocument
doc.subject = "Some mostly harmless planet"

Call args.add( "Tommy Valand" )
Call argumentsAsObject( args )

Call args.add( doc )
Call argumentsAsObject( args )

Call args.add( "Always pack your towel!" )
Call argumentsAsObject( args )
End Sub


If you have an easier way to allow this kind of flexibility please let me know.

3 comments:

Dwight Wilbanks said...

I was thinking about solving this issue with passing a list of variants as a parameter. But, I have not come up to the need yet.

Sub SubC()
 Dim args List As Variant
 Set args("session") = New notessession
 args("num") = 1
 args("str") = "string"
 Call funcC( args)
End Sub
Sub FuncC( args List As Variant)
 Print "session.EffectiveUserName=" & args("session").EffectiveUserName
 Print "num=" & Cstr( args( "num"))
 Print "str=" & args( "str")
End Sub

Sean Burgess said...

I had the exact same thought as Dwight when I was reading your post. Lists are great for handling collections of disparate things. Plus, you can make a List contain another List. Very OO way of looking at and handling data. And because Lists are accessed via parameter name and not a subscript number, you could make the list really dynamic.

Tommy Valand said...

You know what, I hadn't thought of that approach.. :)

Another fun thing with lists is the ListTag:
Sub stampDocuments( args List As Variant )
Dim s As New NotesSession
Dim tempDoc As NotesDocument
Forall arg In Args
%REM
document[ int ] ->
NotesDocument

documentId[ int ] ->
NotesDocument.UniversalID
%ENDREM
If Instr( ListTag( arg ), "Id" Then
Set tempDoc = s.CurrentDatabase.GetDocumentByUNID( arg )
Else
Set tempDoc = arg
End If
tempDoc.stamped = "stamped"
End Forall
End Sub