Tipps & Tricks: Subs und Functions

Subs und Functions oder die Frage: Wie finde ich die richtigen Argumente?

Was ist eine Prozedur? Die Online-Hilfe informiert wie folgt:

Prozedur

Eine benannte Folge von Anweisungen, die als Einheit ausgeführt werden. Function, Property und Sub sind zum Beispiel Prozedurtypen. Der Name einer Prozedur wird immer auf Modulebene definiert. Der gesamte ausführbare Code muß in einer Prozedur enthalten sein. Prozeduren können nicht in andere Prozeduren eingesetzt werden.

oder auch:

  • Eine Sub-Prozedur ist eine Folge von Visual Basic-Anweisungen, die in den Anweisungen Sub und End Sub eingeschlossen sind und Aktionen ausführen, aber keinen Wert zurückgeben. Eine Sub-Prozedur kann Argumente, z.B. Konstanten, Variablen oder Ausdrücke verwenden, die über eine aufrufende Prozedur übergeben werden. Wenn eine Sub-Prozedur über keine Argumente verfügt, muss die Sub-Anweisung ein leeres Klammernpaar enthalten.
  • Eine Function-Prozedur ist eine Folge von Visual Basic-Anweisungen, die durch die Anweisungen Function und End Function eingeschlossen sind. Eine Function-Prozedur ähnelt einer Sub-Prozedur, kann aber auch einen Wert zurückgeben. Eine Function-Prozedur kann Argumente, wie z.B. Konstanten, Variablen oder Ausdrücke verwenden, die über die aufgerufene Prozedur übergeben werden. Wenn eine Function-Prozedur über keine Argumente verfügt, muss deren Function-Anweisung ein leeres Klammernpaar enthalten. Eine Funktion gibt einen Wert zurück, indem ihrem Namen ein Wert in einer oder mehreren Anweisungen der Prozedur zugewiesen wird.
  • Eine Property-Prozedur ist eine Folge von Visual Basic-Anweisungen, die es einem Programmierer ermöglicht, benutzerdefinierte Eigenschaften zu erstellen und zu bearbeiten.
    Property-Prozeduren können zur Erstellung schreibgeschützter Eigenschaften für Formulare, Standardmodule und Klassenmodule verwendet werden.
    Property-Prozeduren sollten anstelle von Public-Variablen in Code verwendet werden, der ausgeführt werden muss, wenn der Wert der Eigenschaft festgelegt wird.
    Im Gegensatz zu Public-Variablen können Property-Prozeduren im Objektkatalog beschreibende Texte zugeordnet sein.

Alles klar? Schön. Dann können wir ja gleich in medias res gehen...

Sub-Routinen geben keinen Wert zurück, Function Routinen können dies jedoch. Richtig? Jain!

Das „Geheimnis“ liegt in der Art, wie Argumente übergeben werden.

Grundsätzlich unterscheidet man bei Argumenten zwischen der Übergabe einer Referenz und der Übergabe eines Wertes. Der Standard ist die Übergabe einer Referenz!

In der Deklaration von Argumenten kann dies explizit durch die Klassifizierung durch ByVal bzw. ByRef erfolgen.

Sub Foo(sMyValue As String)
ist exakt das gleiche wie
Sub Foo(ByRef sMyValue As String)

da ByRef („als Referenz“) der Standard in VB/VBA ist. Erst durch die Änderung in ByVal verändern wir das Argument auf entscheidende Art und Weise.

Sub Foo(ByVal sMyValue As String)
  • Bei der Übergabe einer Referenz wird lediglich der „Zeiger“ auf eine Variable im Speicher übergeben.
  • Bei der Übergabe als Kopie wird eine Kopie der Variable (nebst dessen Inhalt) übergeben.

Beispiel:

' Lassen wir uns überraschen
Sub Main()
 
  Dim sMyValue As String
  sMyValue = "Hallo Welt"
 
  Call Test01(sMyValue)
  Call Test02(sMyValue)
 
  MsgBox sMyValue
 
End Sub
 
Sub Test01(ByRef sMyValue As String)
 
  sMyValue = "Das war's dann..."
  Call Test03(sMyValue)
End Sub
 
Sub Test02(ByVal sMyValue As String)
 
  sMyValue = "Und was jetzt?"
 
End Sub
 
Sub Test03(sMyValue As String)
 
  sMyValue = "Geben wir der Variablen den Rest..."
 
End Sub

Was wird in der Routine Main in der MsgBox angezeigt?

Hier wird (implizit) das Wissen vorausgesetzt, dass man andere Subs durch die Call-Anweisung aufrufen kann...

Erstelle ein neues Modul im VBA-Editor, gib obenstehenden Quellcode ein, führe Sub Main() aus und finde deine Annahme über die Meldung bestätigt (oder auch nicht...).

Die hier dargestellte ByRef- bzw. ByVal-Problematik gilt im Übrigen für sämtliche Prozedurtypen und ist nicht auf Sub-Routinen beschränkt!

HinweisFazit: Man sollte grundsätzlich seine Argumente mit ByVal klassifizieren, um keine unliebsamen Überraschungen zu erfahren. Die Klassifizierung mit ByRef bzw. die Übernahme des Standards sollte nur bewusst in den Fällen erfolgen, bei denen man „etwas“ damit bezweckt.