Wenn ich eine lange Liste von ALV-Spalten habe, die ich in der geschilderten Weise definiere, dann wäre mir der Aufwand, für jedes davon ein Textsymbol zu definieren (was ich für alle anderen Zwecke inzwischen zu machen pflege), einfach zu hoch. Wenn ich wüsste, dass ich eine Vielzahl von Sprachen unterstützen muss, dann würde ich es machen, aber da es eh nur deutsch und englisch ist, ist ein CASE SY-LANGU nebst Copy&Paste der ganzen Definitionszeilen und Überschreiben der deutschen Begriffe mit englischen einfach eine Größenordnung bequemer - und im Code sogar noch besser lesbar, weil statt kryptischen Textsymbolnamen der Klartext dasteht.black_adept hat geschrieben:CASE SY-LANGU und nicht Textsymbole? SLIN wird nie dein Freund werden....
Das muss ich mal drüber nachdenken. Das ist das Einzige, für das mir nicht so recht ein Gegenargument einfällt. Ich liebe dieses Forum; was ich hier trotz meiner Berufserfahrung schon an Informationen und Denkanstößen mitgenommen habe, geht auf keine Kuhhaut.black_adept hat geschrieben:Wenn du schon den ganzen Aufwand treibst - warum dann nicht im DDIC Datenelemente anlegen mit den richtigen Bezeichnungen und damit mit Wiederverwendungsmöglichkeit?
Wenn Dein Programm ein Modulpool ist, ja. Mittlerweile sind aber 98% meiner Programme Reports, so dass es nur ein bildschirmfüllendes Ergebnis-ALV gibt. Technisch sind die Unterschiede natürlich weiterhin vorhanden, in der Praxis jedoch vernachlässigbar. Ich habe in meinem Report eine ALV-Tabelle, und die wird schrittweise und gut kommentiert mit Leben gefüllt. Das ist wunderbar les- und nachvollziehbar, auch ohne dass ich sie als Trivialparameter an jede Unterroutine durchreiche.Ralf hat geschrieben:Nein. Ein Dynpro funktioniert nach einem ganz anderes Prinzip als ein ALV, was man schon daran erkennt, dass ein ALV ein Dynpro braucht.
Und was hast Du davon, mal abgesehen von der durch höheren Programmieraufwand erkauften Political Correctness? Das Problem globaler Tabellen und Variablen ist doch, dass man nicht nachvollziehen kann, wer sie wann und warum befüllt und das Programm dadurch unverständlich und nicht nachvollziehbar wird. Wenn aber (am besten schon durch die Namensgebung der Tabelle) klar (und notfalls durch einen Verwendungsnachweis auf einen Blick beweisbar) ist, dass die Tabelle nur ein einziges Mal schreibend befüllt wird, nämlich zu Programmbeginn, und ihr Zweck offensichtlich ist, dann hat man dieses Problem nicht. Dann ist die Puffertabelle im Programm zu betrachten wie eine Datenbanktabelle. Die definierst Du ja auch nicht lokal.Ralf hat geschrieben:Bei dir vielleicht Ich verwende Klassenattribute (und ja, das ist etwas ganz anderes).DeathAndPain hat geschrieben:Ansonsten sind bei mir auch Puffertabellen global.
Das ist eine sehr akademische Begründung, die nach meiner Überzeugung keinen praktischen Wert hat (wie Du ja auch durch die Formulierung "für mich" implizit einräumst).Ralf hat geschrieben:Es ist eher eine willkürliche ABAP-Erscheinung, dass man einen Variablennamen für unterschiedliche Variablen verwendet und man nur deshalb REFRESH erfindet, obwohl ein CLEAR reicht. Eine Tabelle ist für mich eine Variable und die lösche ich mit CLEAR.
Könnte man machen, aber abgesehen von der schlechteren Performance habe ich dann wieder das Problem, dass ich einen Namen für die Variable brauche, dem man gut ansieht, in welchem Verhältnis er zur Tabelle steht. WA_TABELLENNAME finde ich extrem sperrig, blöd zu tippen (weil man mitten im Variablennamen die Shift-Taste braucht) und vor allem optisch sehr hässlich und damit trotz der Klarheit der Benamung ein Problem für die Lesbarkeit. Da gefällt mir <TABELLENNAME> bedeutend besser. Das ist zwar auch blöd zu tippen (was ja mein verbleibender Kritikpunkt war), aber zumindest optisch macht das echt was her. *TABELLENNAME wäre freilich mein Favorit gewesen, besonders mit impliziter Definition (soll heißen, dass sollte es für alle internen Tabellen ohne explizite Deklaration automatisch geben. Selbst wenn man es im Einzelfall nicht braucht: Über den Speicherverbrauch einer einzelnen Kopfzeile brauchen wir heutzutage ja wohl nicht zu reden. Und wenn gar *TABELLENNAME eine Spezialform eines Feldsymboles wäre und dann am besten noch automatisch als Ziel bei "LOOP AT TABELLENNAME." genutzt werden würde, dann wäre damit sogar noch der Speicherverbrauch und Performancenachteil vom Tisch, und der Code wäre kürzer). Das wäre IMHO ein echter Gewinn für ABAP.Ralf hat geschrieben:Lösung: LOOP AT variable INTO DATA(variable)
Hm. Bevor ich (damals autodidaktisch anhand eines Einsteigerbuches) ABAP erlernt habe, hatte ich schon jahrelang alle möglichen BASIC-Dialekte programmiert und überdies noch an der Uni mit Programmiersprachen zu tun (darunter so geisteskrankes Zeug wie PROLOG). Trotzdem habe ich den Sinn von Kopfzeilen sofort verstanden und hatte mit diesem Detail nicht die geringsten Probleme. Die Eigenheiten von Dynpros zu verstehen finde ich da schon etwas anspruchsvoller. Und wie gesagt, was Referenzvariablen einem Programmierer abfordern, ist um Größenordnungen komplexer zu überblicken. Du kritisierst Variablen, die sich einen Namen teilen, aber Variablen, die gar keinen Namen haben, sind ok...Das und implizite Kopfzeilen sind Dinge, deren Verständnis denen sehr schwer fällt, die aus anderen Programmiersprachen kommen.
Das hast Du schon öfter erwähnt. Es wäre nett, wenn Du dazu mal ein bisschen Beispielcode bieten könntest, der die Funktionsweise veranschaulicht. Ich bin ja neuen Ansätzen gegenüber durchaus aufgeschlossen, wenn ich ihnen einen praktischen Nutzen abgewinnen kann. Von VALUE und CONV bin ich inzwischen ein ganz großer Fan, und selbst die komischen SWITCH- und COND-Befehle habe ich inzwischen ins Herz geschlossen.Man kann mit Ausnahmeklassen irre Sachen machen, wenn man ein bisschen kreativ ist. Früher hab ich die Dinger gehasst wie die Pest, aber seit ich z. B. weiß, wie ich komplette Protokolle durch Verschachteln von Ausnahmen zusammenbauen kann, die ich dann einmal "auspacke" und ins Anwenderlog schreibe (mit einer generischen Klasse, die ich einmal geschrieben habe für das ganze System), bin ich ein echter Fan davon, weil ich dazu nix mehr selbst machen muss.
Der Aufwand beschränkt sich auf einen Doppelklick. Im Coding steht dann 'Ich bin ein Textsymbol(nnn)', wobei nnn die laufende Nummer ist. Das ist selbsterklärend und schnell gemacht.DeathAndPain hat geschrieben:Wenn ich eine lange Liste von ALV-Spalten habe, die ich in der geschilderten Weise definiere, dann wäre mir der Aufwand, für jedes davon ein Textsymbol zu definieren (was ich für alle anderen Zwecke inzwischen zu machen pflege), einfach zu hoch. Wenn ich wüsste, dass ich eine Vielzahl von Sprachen unterstützen muss, dann würde ich es machen, aber da es eh nur deutsch und englisch ist, ist ein CASE SY-LANGU nebst Copy&Paste der ganzen Definitionszeilen und Überschreiben der deutschen Begriffe mit englischen einfach eine Größenordnung bequemer - und im Code sogar noch besser lesbar, weil statt kryptischen Textsymbolnamen der Klartext dasteht.black_adept hat geschrieben:CASE SY-LANGU und nicht Textsymbole? SLIN wird nie dein Freund werden....
Nein, das Eventhandling ist ein ganz anderes.DeathAndPain hat geschrieben:Wenn Dein Programm ein Modulpool ist, ja. Mittlerweile sind aber 98% meiner Programme Reports, so dass es nur ein bildschirmfüllendes Ergebnis-ALV gibt. Technisch sind die Unterschiede natürlich weiterhin vorhanden, in der Praxis jedoch vernachlässigbar.Ralf hat geschrieben:Nein. Ein Dynpro funktioniert nach einem ganz anderes Prinzip als ein ALV, was man schon daran erkennt, dass ein ALV ein Dynpro braucht.
Nur ein Beispiel: Die Klasse kann ich kapseln und unsinnige Werte gleich abweisen, indem ich sie durch SET-Methoden zuweise. Das kann Vorteile bringen. Außerdem hat jeder Entwickler einen "Stil" und wer sich in meine Programme einarbeitet, muss nicht mal so und mal so denken, je nach Fall.DeathAndPain hat geschrieben:Und was hast Du davon, mal abgesehen von der durch höheren Programmieraufwand erkauften Political Correctness? Das Problem globaler Tabellen und Variablen ist doch, dass man nicht nachvollziehen kann, wer sie wann und warum befüllt und das Programm dadurch unverständlich und nicht nachvollziehbar wird.
Ich arbeite viel mit Leuten zusammen, die nicht aus der ABAP-Welt kommen und die haben (wie gesagt) immer mit denselben Konstrukten Probleme - zum Beispiel mit impliziten Kopfzeilen.DeathAndPain hat geschrieben:Das ist eine sehr akademische Begründung, die nach meiner Überzeugung keinen praktischen Wert hat (wie Du ja auch durch die Formulierung "für mich" implizit einräumst).Ralf hat geschrieben:Es ist eher eine willkürliche ABAP-Erscheinung, dass man einen Variablennamen für unterschiedliche Variablen verwendet und man nur deshalb REFRESH erfindet, obwohl ein CLEAR reicht. Eine Tabelle ist für mich eine Variable und die lösche ich mit CLEAR.
Das fehlt es mir an der Zeit für ein Codebeispiel. Prinzip ist: Du wirfst eine Ausnahme, die du außen fängst und mit "previous" in die nächste Ausnahme wirfst. Das geht tief geschachtelt, so dass du nachher eine Ausnahme hast, darin eine vorhergehende Ausnahme und darin wieder eine vorhergehende Ausnahme. Das in ein Protokoll geschrieben und ins Anwenderlog und schon kannst du nachvollziehen, was alles passiert ist. Das ist gerade bei Ausnahmen gut, die nicht zwingend einen Programmabbruch zur Folge haben müssen.DeathAndPain hat geschrieben:Das hast Du schon öfter erwähnt. Es wäre nett, wenn Du dazu mal ein bisschen Beispielcode bieten könntest, der die Funktionsweise veranschaulicht. Ich bin ja neuen Ansätzen gegenüber durchaus aufgeschlossen, wenn ich ihnen einen praktischen Nutzen abgewinnen kann. Von VALUE und CONV bin ich inzwischen ein ganz großer Fan, und selbst die komischen SWITCH- und COND-Befehle habe ich inzwischen ins Herz geschlossen.Man kann mit Ausnahmeklassen irre Sachen machen, wenn man ein bisschen kreativ ist. Früher hab ich die Dinger gehasst wie die Pest, aber seit ich z. B. weiß, wie ich komplette Protokolle durch Verschachteln von Ausnahmen zusammenbauen kann, die ich dann einmal "auspacke" und ins Anwenderlog schreibe (mit einer generischen Klasse, die ich einmal geschrieben habe für das ganze System), bin ich ein echter Fan davon, weil ich dazu nix mehr selbst machen muss.
Du lässt es einfacher klingen, als es ist. Wenn ich den Klartext im Coding eintrage, dann steht da der Name des Feldes, dem ich als der Entwickler in aller Regel schon aus dem Kopf eine passende Spaltenüberschrift zuordnen kann. So schreibe ich das flüssig herunter, an der Stelle, an der auch die anderen Eigenschaften des ALV-Feldes stehen.Der Aufwand beschränkt sich auf einen Doppelklick. Im Coding steht dann 'Ich bin ein Textsymbol(nnn)', wobei nnn die laufende Nummer ist. Das ist selbsterklärend und schnell gemacht.
Es ging hier aber nicht um OO im Allgemeinen, sondern ganz konkret um Puffertabellen für Datenbankwerte. Wir reden hier von einer primitiven Puffertabelle, die einfach nur Zeilen aus der Datenbanktabelle für schnellen Zugriff vorhält. Wenn Du darin "unsinnige Werte" hast, dann hast Du ein Problem, das mit Pufferung nichts zu tun hat, denn dann stehen diese Werte auch in Deiner Datenbanktabelle.Nur ein Beispiel: Die Klasse kann ich kapseln und unsinnige Werte gleich abweisen, indem ich sie durch SET-Methoden zuweise.
Schon mal folgende Angabe versucht?DeathAndPain hat geschrieben:Du lässt es einfacher klingen, als es ist. Wenn ich den Klartext im Coding eintrage, dann steht da der Name des Feldes, dem ich als der Entwickler in aller Regel schon aus dem Kopf eine passende Spaltenüberschrift zuordnen kann. So schreibe ich das flüssig herunter, an der Stelle, an der auch die anderen Eigenschaften des ALV-Feldes stehen.
Schreibe ich jedoch Textsymbole und mache dabei das, was bei Variablen verpönt ist, aber leider üblich und hier von Dir propagiert wird, nämlich völlig aussagelose Namen für die Textsymbole (wobei das 3-Zeichen-Limit sicherlich nicht hilfreich ist), dann habe ich anschließend eine Liste von Textsymbolen T01 bis T27. Und dann darf ich immer hin- und herspringen, um zu schauen, von welchem Feld das denn jetzt der Überschriftstext sein soll. Oder ich arrangiere mir einen Splitscreen mit dem Code links und den Textsymbolen rechts und flitze mit den Augen immer hin und her. Klar kann man das machen. Aber dass der Mehraufwand nur ein Doppelklick sei, ist ein Gerücht.
Code: Alles auswählen.
lv_field-coltext = 'ich bin ein Text mit Textsymbol'(T01).
Die meinte ich.a-dead-trousers hat geschrieben:Schon mal folgende Angabe versucht?Code: Alles auswählen.
lv_field-coltext = 'ich bin ein Text mit Textsymbol'(T01).
Und damit wird dann SLIN doch wieder zum Freund und man hat sogar einen Default für nicht übersetzte Symbole.a-dead-trousers hat geschrieben:Code: Alles auswählen.
lv_field-coltext = 'ich bin ein Text mit Textsymbol'(T01).
Du schreibst den Text hin und machst einen Doppelklick darauf. Sodann wird ein Textelement mit eben diesem Text angelegt und die Nummer wird hinter dem Literal automatisch eingefügt. Das führt dazu, dass du mit einfachen Mitteln ein Textelement anlegst (du brauchst dich um die Nummerierung auch nicht zu kümmern) und es außerdem als Default für alle nicht übersetzen Sprachen gilt (weil es ein Textelement der Originalsprache ist).DeathAndPain hat geschrieben:Diese Syntax kenne ich nicht. Kann mir bitte jemand erklären, was sie tut? Einen Text im Klartext anzugeben und zugleich auf ein Textsymbol zu verweisen, kommt mir irgendwie widersprüchlich vor.
Folgende Benutzer bedankten sich beim Autor ralf.wenzel für den Beitrag:
DeathAndPain
Ich habe gerade eines geschrieben für einen anderen Zweck:
Code: Alles auswählen.
*&---------------------------------------------------------------------*
*& Report ZZRWTEST
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zzrwtest.
" written as test class - start with Strg+F10 (!)
*----------------------------------------------------------------------*
* CLASS lcl_raise_kaskade_demo DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_raise_kaskade_demo DEFINITION FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
* ================
CLASS-DATA:
texts TYPE STANDARD TABLE OF string.
CLASS-METHODS:
"! logging method
"!
"! @parameter i_any | any error
logger
IMPORTING
i_any TYPE any.
METHODS:
raiser FOR TESTING.
ENDCLASS. "lcl_raise_kaskade_demo
*----------------------------------------------------------------------*
* CLASS lcl_raise_kaskade_demo IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_raise_kaskade_demo IMPLEMENTATION.
METHOD raiser.
DATA exc TYPE REF TO cx_root.
DATA descr TYPE REF TO cl_abap_typedescr.
DATA bapiret2 TYPE bapiret2.
DATA bapiret2tab TYPE bapiret2tab.
TRY.
" raise an exc
RAISE EXCEPTION TYPE cx_aunit_prog_access
EXPORTING
textid = cx_aunit_prog_access=>cx_aunit_prog_access
program_name = 'BLA'.
CATCH cx_aunit_prog_access INTO exc.
TRY.
" raise another exc and register previous
RAISE EXCEPTION TYPE cx_bgrfc_invalid_destination
EXPORTING
textid = cx_bgrfc_invalid_destination=>inbound_dest_not_registered
previous = exc
dest_name_inbound = 'BLUB'.
CATCH cx_bgrfc_invalid_destination INTO exc.
" example 1: write exc-package to log
logger( exc ).
" example 2: write bapiret2-structure to log
logger( bapiret2 ).
" example 3: write bapiret2-table to log
logger( bapiret2tab ).
" there may be many other cases
" (symsg, syst, ....)
ENDTRY.
ENDTRY.
ENDMETHOD. " raiser
METHOD logger.
DATA descr TYPE REF TO cl_abap_typedescr.
DATA exc TYPE REF TO cx_root.
DATA text TYPE string.
TRY.
" for exc: unpack package recursively
descr = cl_abap_typedescr=>describe_by_object_ref( i_any ).
exc = i_any.
IF exc->previous IS NOT INITIAL.
logger( exc->previous ).
ENDIF.
" get text and write it to log (SBAL or log table)
text = exc->get_text( ).
" in this case: collect message texts in itab
INSERT text INTO TABLE texts.
BREAK-POINT. " have a look to table TEXTS!
CATCH cx_sy_dyn_call_illegal_type.
" for structures and tables: write to log
descr = cl_abap_typedescr=>describe_by_data( i_any ).
CASE descr->kind.
" just one message
WHEN cl_abap_typedescr=>kind_struct.
" write to log
" message table
WHEN cl_abap_typedescr=>kind_table.
" write to log in a LOOP
" literal, single field
WHEN cl_abap_typedescr=>kind_elem.
" write comment to log
WHEN OTHERS.
" throw exc
ENDCASE.
ENDTRY.
ENDMETHOD. "logger
ENDCLASS. "lcl_raise_kaskade_demo
Folgende Benutzer bedankten sich beim Autor ralf.wenzel für den Beitrag (Insgesamt 2):
Looper • SaskuAc