Matlab (MATrix LABoratory) wird oft in wissenschaftlichen und ingenieurtechnischen Feldern angewendet. Es ist eine Spezialsoftware für numerische und symbolische Mathematik. Weniger bekannt hingegen ist, dass Matlab auch objektorientierte Programmierung (OOP) unterstützt. In diesem Blogartikel möchte ich auf diese Möglichkeit und ihre Tücken kurz eingehen.
Wer mit Matlab arbeitet, kennt es allzu gut. Es können schnell lange, unübersichtliche Skripte entstehen, denn Matlab wird auch gern genutzt, um eben mal Daten grafisch in einem Plot darzustellen. Oft höre ich „das ist historisch gewachsen“. Ich selbst denke mir dann, das muss doch irgendwie hübscher und weniger redundant gehen? Außerdem wäre es schön, wenn das Skript auf einfache Weise erweiterbar wäre. Also wie es bestimmte Techniken der objektorientierten Programmierung erlauben.
Es gibt OOP in Matlab?
Wie bereits erwähnt ist OOP auch in Matlab möglich. Seit der Version R2008a gibt es in Matlab Klassen mit Properties, Methoden und Vererbung. Jedoch musst du bei der Verwendung von solchen Mitteln in Matlab ganz schön auf die Laufzeiten aufpassen. Vor allem sind die Laufzeiten stark abhängig davon, welche Version du verwendest. Dazu später mehr.
Beispiel „Log Levels“
Schauen wir uns anhand eines Beispiels an, wie OOP in Matlab aussehen kann:
Ich möchte gern Log-Nachrichten konfigurieren und den entsprechenden Log-Level anzeigen. Ein ähnliches Konzept gibt es bereits in anderen Programmiersprachen, zum Beispiel in Python (Logging Levels). Die verschiedenen Typen sollen also eine Ordnung erhalten, die den Grad der Risikobewertung widerspiegelt (Order). Je niedriger die Ordnungszahl ist, desto kritischer soll die Lognachricht sein.
1. Variante: Enumeration
Ein plausibles erstes Mittel sind Aufzählungstypen (Enumeration Types). Tatsächlich gibt es auch in Matlab Enumerations. Es ist daher naheliegend, diese Variante auch auszuprobieren. Um die Ordnung zu integrieren, leitet die Basisklasse LoggingEnum
von der Integer-Datentypgröße uint8
(8-Bit-Integer-Arrays ohne Vorzeichen) ab. Eine Vererbung von Klassen wird in Matlab durch das Zeichen <
angegeben. Um die Bezeichnung eines Log-Levels später in Texten anzeigen zu können, füge ich noch eine Methode get_description
hinzu, welche mir den Namen als String zurück gibt.
classdef LoggingEnum < uint8 %Defines default log-level types to use it later at log messages. %The lower the order, the more critical the log message. enumeration Debug (4) Info (3) Warning (2) Error (1) FatalError (0) end methods function description = get_description(loglevel) description = char(loglevel); end end end
Die Ausgabe eines Enumeration im Command Window in Matlab sieht dann so aus:
>> info = LoggingEnum.Info
info =
LoggingEnum enumeration
Info
Die Methoden einer Klasse lassen sich entweder durch die neue Syntax obj.method
>> this_description = LoggingEnum.Info.get_description this_description = Info
oder auch klassisch durch die Syntax method(obj)
aufrufen:
>> this_description = get_description(LoggingEnum.Info) this_description = Info
Jedoch möchte ich hier schon erwähnen, dass der Aufruf über die Syntax obj.method
sehr langsam und nicht zu empfehlen ist! Generell sorgen Enumerations in Matlab für schlechte Performance. Deshalb lohnt es sich, auch andere Implementierungen anzuschauen.
2. Variante: Klasse mit konstanten Properties
Eine andere Möglichkeit wäre es, eine Klasse (siehe auch doc classdef) mit dem Namen LogLevel
und einer Ordnung und Typbeschreibung als Properties zu erstellen. Der Konstruktor weist die Typbezeichnung und die Ordnung zu. In Matlab sieht das dann folgendermaßen aus:
classdef LogLevel %Defines description and order for log levels properties Description Order end methods function obj = LogLevel(this_description, this_lvl) obj.Description = this_description; obj.Order = this_lvl; end end end
Außerdem erstelle ich eine Klasse Logging
mit konstanten Properties, welche mir die Log-Level mit den passenden Typbezeichnungen definiert, indem entsprechend Objekte von der Klasse LogLevel
erstellt werden:
classdef Logging %Defines default log-level types to use it later at log messages. properties (Constant = true) Debug = LogLevel('Debug', 4) Info = LogLevel('Info', 3) Warning = LogLevel('Warning', 2) Error = LogLevel('Error', 1) FatalError = LogLevel('FatalError', 0) end end
Im Command Window kann ich diese konstanten Properties direkt verwenden:
>> info = Logging.Info
info =
LogLevel with properties:
Description: 'Info'
Order: 3
Der Nachteil ist, dass ich nun zwei Klassen brauche. Außerdem lassen sich die Enumerations direkt vergleichen, während ich in der Klasse LogLevel
das Property Order
dafür erstellen musste. Hier nochmal der Vergleich für Klassen mit konstanten Properties vs den Enumerations:
>> is_loglevel_info = Logging.Info.Order == 3 is_loglevel_info = 1 >> is_enum_info = LoggingEnum.Info == 3 is_enum_info = 1
3. Variante: Funktion mit „struct“ als Ausgabe
Eine eher herkömmliche Variante in Matlab ist eine Funktion, die den Datentyp „struct“ zurückgibt, welcher den Level und die Typbezeichnung des gewünschten Log-Typs enthält:
function logging = func_loglevel(lvl) %Defines loglevel types loglevel = struct( 'Description', [],... 'Order', lvl); if lvl == 4 loglevel.Description = 'Debug'; elseif lvl == 3 loglevel.Description = 'Info'; elseif lvl == 2 loglevel.Description = 'Warning'; elseif lvl == 1 loglevel.Description = 'Error'; elseif lvl == 0 loglevel.Description = 'FatalError'; end end
Die Ausgabe im Command Window würde dann folgendermaßen aussehen:
>> info = func_loglevel(3)
info =
struct with fields:
Description: 'Info'
Order: 3
>> this_lvl = info.Order
this_lvl = 3
Laufzeitanalyse
Nachdem ich einige Varianten vorgestellt habe, möchte ich auf die Laufzeiten eingehen. Andrew Janke hat eine nette Übersicht über die möglichen Laufzeiten in Abhängigkeit der Matlab-Version erstellt. Der Quellcode ist auch auf GitHub hochgeladen. Damit kannst du recht unkompliziert dein System testen.
Ich habe die Laufzeiten auf zwei unterschiedlichen Systemen getestet, indem ich die jeweilige Description-Ausgaben meiner Log-Level-Varianten aufgerufen habe. Diese ließ ich mit 100.000 Iterationen durchlaufen.
nIters = 100000; name = 'enumeration, using .method'; t0 = tic; for i = 1:nIters obj = LoggingEnum.Debug; obj.get_description; end te = toc(t0); show_result(name, nIters, te); name = 'enumeration, using method()'; t0 = tic; for i = 1:nIters obj = LoggingEnum.Debug; get_description(obj); end te = toc(t0); show_result(name, nIters, te); name = 'class, constant properties'; t0 = tic; for i = 1:nIters obj = Logging.Debug; obj.Description; end te = toc(t0); show_result(name, nIters, te); name = 'struct'; t0 = tic; for i = 1:nIters obj = func_loglevel(4); obj.Description; end te = toc(t0); show_result(name, nIters, te);
Dabei haben sich folgende Zeiten ergeben:
R2013b, Windows 8, [sec]/100.000 | R2021b, Windows 10, [sec]/100.000 | |
Funktion mit Ausgabeparameter vom Typ „struct“ | 9.32 | 3.77 |
Enumeration mit Syntax „obj.method“ | 13.08 | 18.63 |
Enumeration mit Syntax „method(obj)“ | 10.38 | 8.66 |
Klasse mit konstanten Properties | 7.80 | 2.40 |
Die schnellste Variante ist also die Verwendung einer Klasse mit konstanten Properties. Wenn ich die Zeiten nach der schnellsten Laufzeit normiere, dann ist die Verwendung von Enumerations im besten Fall (R2013, „method(obj)“) 1,3- und im schlechtesten Fall (R2021, „obj.method“) sogar 7,7-fach langsamer. Bei der Verwendung einer Funktion, die ein „struct“ zurückgibt, ist die Laufzeit 1,2- bis 1,6-fach langsamer.
Besonders ins Auge fallen allerdings die Zeiten für die unterschiedlichen Syntaxvarianten für die Methoden einer Klasse. Mit dem Release R2013b ist der Aufruf mittels „obj.method“ 1.26-fach langsamer als der Aufruf mittels „method(obj)“ und mit dem Release R2021b sogar 2.15-fach langsamer.
Fazit
Durch den Einsatz von OOP kann die Wartbarkeit von Software sehr profitieren. Diese Vorteile lassen sich auch in Matlab nutzen, wovon ich mit diesem Artikel einen ersten Eindruck bieten will. Bei der Benutzung von Klassen oder Enumerations können die Laufzeiten allerdings je nach Matlab-Version deutlich variieren.
Mehr Informationen zum Thema Software Engineering findest du hier in unserem Kompetenzfeld.
- Matlab, Objektorientierte Programmierung (OOP) und Laufzeiten - 4. November 2022