Seite 1 von 1

PB4 + LinkedLists + Proceduren

Verfasst: 09.03.2006 12:51
von Hyper
Hallo Gefährten,

ich habe mir Beta5 von PB 4.0 angeschaut und bin ja begeistert! Viele bislang sehnlichst vermisste Dinge (readOnly beim Editor Gadget etc...)

Was mich aber besonders freut, ist das man nun LinkedLists lokal definieren und in Proceduren übergeben kann.

Hierzu habe ich 2 Fragen:
1. Kann man diese auch aus Proceduren wieder zurückgeben?
2. Kann man Listen ohne Loop kopieren?

Etwa so (schnell mal ohne Editor):

Code: Alles auswählen

NewList Liste.Typ()                             ; Deklaration

Procedure List_aufraeumen(Input_Liste.Typ())     ; Übergabe an Proc

  Protected NewList Lokale_Liste.Typ()
  
  Lokale_Liste() = Input_Liste()  ; Geht so etwas = Frage 1?

  ; Liste bearbeiten
  ; ......

  ProcedureReturn ;Lokale_Liste() als Liste zurück, aber ... Wie = Frage 2??

Endprocedure

; -----------------
; Hauptprogramm

List_aufraeumen(Liste())


Verfasst: 11.03.2006 22:14
von technicorn
Hi,

das mit dem zurückgeben kann nie gehen, da die lokale Liste beim beenden
der Procedure, wie auch alle anderen lokalen Variablen, vom Stapel entfernt werden.

Willst Du ein Liste in der Procedure verändern, einfach als Parameter übergeben,
die Proc. arbeitet dann mit der übergenen Liste und alle Änderungen sind
auch nach dem Ende noch da.

Kopieren kann nur mit einer Schleife gehen, da jedes Element der Liste
irgendwo im Speicher liegt und nicht wie bei Arrays hintereinander.

Z.z. giebt es meines Wissens in PB keinen Befehl dafür.

Gruß
technicorn

Verfasst: 12.03.2006 01:50
von Hyper
@technicorn: Danke Dir für die Bestätigung!

@all:

zum Thema Listen an Procedures übergeben habe ich weiter getestet:

1. Linked Lists als optionale Funktionsparameter nicht möglich
Zu PB4 wurden für Proceduren a) optionale Parameter eingeführt und b) die Möglichkeit, LinkedLists als Parameter zu übergeben. Offenbar aber mit XOR, d.h. nicht beides gleichzeitig.

2. Uneinheitliche Behandlung von übergebenen LinkedLists und sonstigen Parametern
Übergibt man in einem Procedure-Aufruf eine Variable, dann ist dies unidirektional, sollte die Variable in der Procedure geändert werden, wird sie nicht im aufrufenden Hauptprogramm geändert. Bei Listen verhält es sich hier anders. Dort wird direkt in der übergebenen Liste geändert.

3. Listen können nicht ProcedurereReturn sein
Beispiel: Man möchte das Erzeugen einer Liste in einer Proc. kapseln
(Generell wäre es auch schön, wenn der ProcedurereReturn zumindest eine Struktur sein könnte, da bräuchte man nicht zu "pointern")

Insbesondere Punkt 1 ist meines Erachtens nicht gut, da nicht konsequent. Wie seht Ihr das und die anderen Punkte?

Verfasst: 12.03.2006 03:54
von technicorn
Zu 1.
Das würde meines Erachtens auch wenig Sinn machen, da Du in der Procedure keine Möglichkeit hättest, zu prüfen ob die Liste da ist oder nicht.
Und was willst Du optional für die List übergeben?

Zu 2.
Das hängt mit dem Programmaufbau zusammen ->
Parameter ist eine einfache Variable -> Du arbeitest in der Proc. mit einer
Kopie der Daten.

Parameter ist ein Array/Liste -> Nur ein Zeiger auf das Array/ die List
wird übergeben, die Proc. arbeitet direkt mit den Daten,
ist das Gleiche als wenn Du einen Zeiger auf eine Variable übergibts!

Zu 3.
Programmtechnisch wegen der Stapelsache nicht möglich.
Alles was in der Procedur mit Protected erzeugt wird ist nur solange
auf dem Stapel, bis die Procedure endet.
Was mit Static erzeugt wird, bleibt zwar zwichen den Aufrufen erhalten, ist aber nur innerhalb der Procedur sichtbar.
Eine dynamische Erzeugung von Arrays/Listen ist in PB (noch) nicht vorgesehen.

Es ist ja auch noch nicht möglich, Listen zu erstellen die Listen enthalten, wäre aber extrem sinnvoll, weil damit auf einfache Weise eine Baumstruktur erzeugt werden könnte.
Lösche ich dann ein Listenelement, das eine andere Liste enthält, würde die (Sub)List dann automatisch gelöscht.

Bei Listen, die Strings enhalten ist es ja auch so, in der Liste selbst ist
nur ein Zeiger auf den String, der irgendwo im Speicher liegt und ausserdem
bei jeder neuen Zuweisung an einen anderen Platzt verlegt wird.
Wird jetzt ein Listenelement gelöscht, das einen String enhält, wird automatisch der Zusäztliche
Speicher des Strings mit freigegeben.

Noch Fragen? :twisted: :wink:

cu
technicorn

Verfasst: 12.03.2006 12:33
von Hyper
Nun, Du erklärst, warum es nicht (so einfach) geht. Ist ja auch ok. Ich blicke aber aus Sicht des Anwenders der Programmiersprache und da bin ich halt bspw. von ABAB/4 relativ verwöhnt.

Als Nutzer der Sprache halte ich es für meine Aufgabe, zu sagen was sinnvoll wäre, was dann wie umzusetzen ist, müssen dann die Macher der Sprache sagen. Und da bleibt es bspw. nicht logisch, wenn es optionale Parameter gibt, dass Listen nicht optional sein können. Mit CounList kann man in der Procedure ja sehr einfach ermitteln, ob eine Liste reinkam oder nicht.

Verfasst: 12.03.2006 14:02
von technicorn
Hallo Hyper,

ich vermisse bei PB auch so einige Sachen, insbesondere rund um Arrays/Listen.
In XBasic, was leider schon seit Jahren nicht Weiterentwickelt wird,
gibt es sogar die Möglichkeit, unregelmäßige Arrays zu erzeugen, bzw.
man kann einzelne Teile aus dem Array ausklinken und an andere wieder
anhängen.

Ich weiß auch nicht so genau, wieviele nun tatsächlich an der Entwicklung von PB arbeiten,
es sieht aber so aus, daß es ein Einmann Job ist, und dafür ist gegenüber PB3.94 einiges (sehr gutes) passiert.

Was ich jetzt noch nicht verstehe, wieso willst Du eine Proc. aufrufen,
die mit Listen arbeiten soll, und dann keine Übergibts?

Hab's mahl kurz probiert, was viel problematischer ist, finde ich,
daß es bei Proc. nicht möglich ist verschieden Typen von Listen zu übergeben,
um dann z.B. je nach Typ die Daten zu bearbeiten.
Aber das geht wohl schon in Richtung Funktionsüberladung, wie in C++, Java, und ist für die meisten eher nicht einzusetzen.
Muß dann halt eine Proc. für jeden Typ schreiben,
was auf der anderen Seite auch schnelleren Code bringt,
keine Abfrage von Typen usw.

Verfasst: 12.03.2006 17:40
von Hyper
Hallo technicorn,
...und dafür ist gegenüber PB3.94 einiges (sehr gutes) passiert.
Das sehe ich ganz genau so! Ich bin wirklich ein großer Fan von PB und deshalb war ich auch begeistert, dass PB4 rauskam. Um so mehr habe ich natürlich Interesse am weiteren Ausbau der Sprache.
Was ich jetzt noch nicht verstehe, wieso willst Du eine Proc. aufrufen,
die mit Listen arbeiten soll, und dann keine Übergibts?
Wenn es Gründe gibt, normale Variablen als optional zu kennzeichnen, gibt es auch welche, um das für Arrays und Listen zu tun. Um so mehr wir mit optionalen Parametern arbeiten werden, desto häufiger werden uns hier Fälle begegnen, denke ich.

Verfasst: 12.03.2006 18:06
von ts-soft
Hyper hat geschrieben: Wenn es Gründe gibt, normale Variablen als optional zu kennzeichnen, gibt es auch welche, um das für Arrays und Listen zu tun. Um so mehr wir mit optionalen Parametern arbeiten werden, desto häufiger werden uns hier Fälle begegnen, denke ich.
Für Listen oder Arrays kann ich mir keinen Grund für Optionalität vorstellen
:mrgreen:
Wenn Du dafür ein sinnvolles Beispiel hättest, würde mich aber wundern :wink:

Verfasst: 26.03.2006 00:27
von In_Go
Hallo!

Ihr habt viel über unmögliches (?) geschrieben habt aber den Kern der
Sache aus den Augen verloren!

Dabei ists ganz einfach!
Man definiert eine linkedList und übergibt Sie an die Procedure
Innerhalb der Procedure wird die linkedListe Verändert
Die Änderung ists nach der Rückkehr immer noch da!
Die Liste mus dazu nicht mal Global sein!

Also:

Code: Alles auswählen

;Beispiel für Parameterübergabe von Listen an Unterprogramme
;Beispiel für Errechnung der Indizes im Scrollgadget
;Beispiel für With und Endwith
;DIES SOLLTE ALLE DEINE FRAGEN BEANTWORTEN
;UND IST EIN GUTES BEISPIEL FÜR DIE NEUERUNGEN VON PB$
; DANKE FRED! 
Structure TableLine 
  index.l 
  y.l 
  yl.l 
EndStructure 

Structure TableColumn 
  x.l 
  y.l 
  xl.l 
  yl.l 
  name.s 
  id.l 
EndStructure 
Structure Gad
  x.l
  y.l
  b.l
  h.l
  Gadgetart.l 
  Spalte.l
  Zeile.l
  Nummer.l
EndStructure
Enumeration 
  #Window_0 
EndEnumeration
Global GGAD.l
Global GWB.l
Global GWH.l

Procedure PlusGadget(gadgetnummer.l,x.l,y.l,h.l,b.l,zeile.l,spalte.l,G.gad())
  GGAD.l + 1
  SetGadgetData(gadgetnummer.l,GGAD.l)
  AddElement(G())
  With G()  
  \Nummer=gadgetnummer.l :\x=x.l : \y=y.l :\h=h.l : \b=b.l :\Gadgetart=GadgetType(gadgetnummer) 
  \zeile=zeile.l : \spalte=spalte.l
  EndWith
EndProcedure
Procedure TableGadget(GadgetNr,x,y,width,height,name$,SpaltenBreite,TLL.TableLine(),TCL.TableColumn(),G.gad()) 
  If CreateGadgetList(WindowID(#Window_0)) 
    ScrollAreaGadget(GadgetNr, x, y, width, height, 80, 20,  15, #PB_ScrollArea_Single)
    plusgadget(Gadgetnr,x,y,width,height,-1,-1,G())
    AddElement(TLL()) ;Neue Zeile
    AddElement(TCL()) ;Neue Spalte
    With TCL()
    \x=30 : \y=0 : \xl=SpaltenBreite :\yl=20  :\name=name$ 
    \id=ButtonGadget(#PB_Any, \x, \y, \xl, \yl, \name, #PB_Button_MultiLine) 
    plusgadget(\id,\x,\y,\xl,\yl,0,1,G()) 
    EndWith
    CloseGadgetList() 
  EndIf 
EndProcedure 

Procedure AddTableColumn(GadgetNr,Position,name$,Breite,TCL.TableColumn(),G.Gad()) 
  OpenGadgetList(GadgetNr) 
  istbreite=GetGadgetAttribute(GadgetNr,#PB_ScrollArea_InnerWidth) 
  SetGadgetAttribute(GadgetNr,#PB_ScrollArea_InnerWidth,Breite+istbreite) 
  LastElement(TCL()) 
  With TCL()
  x = \x  : y = \y :xl= \xl : yl= \yl  
  AddElement(TCL()) 
  \x=x+xl : \y=y : \xl=Breite : \yl=yl : \name=name$ 
  \id=ButtonGadget(#PB_Any, \x, \y, \xl,\yl,\name, #PB_Button_MultiLine) 
  plusgadget(\id,\x,\y,\xl,\yl,0,CountList(TCL()),G())  
  EndWith
  CloseGadgetList() 
EndProcedure 
;Nun kann man Unterprogramme schreiben die allgemein gültig sind!
Procedure AddTableLine(GadgetNr,TLL.TableLine(),TCL.TableColumn(),G.gad()) 
  OpenGadgetList(GadgetNr) 
  isthoehe=GetGadgetAttribute(GadgetNr,#PB_ScrollArea_InnerHeight) 
  SetGadgetAttribute(GadgetNr,#PB_ScrollArea_InnerHeight,15+isthoehe) 
  Spaltenanzahl = CountList(TCL()) 
  LastElement(TLL()) 
  With TLL()
  index=\index : y=\y : yl=\yl 
  AddElement(TLL()) 
  \index=index+1 : \y=y+yl :\yl=15
  indextaste=ButtonGadget(#PB_Any,0,\y+20,30,15,Str(\index))
  plusgadget(indextaste,0,\y+20,30,15,  \index ,0,G()) 
  EndWith 
   ForEach TCL() 
    With TCL()
    x=\x :y=\yl+TLL()\y : xl=\xl  : yl=TLL()\yl
    EndWith
    mp=StringGadget(#PB_Any,x,y,xl-2,yl-1,"",#ES_MULTILINE|#PB_String_BorderLess) 
    plusgadget(mp,x,y , xl-2 , yl-1 , CountList(TLL())-1 , ListIndex(tcl())+1 , G() )
    ;#PB_String_MultiLine gibts nicht mehr, #ES_MULTILINE scheint identisch zu sein
  Next 
  CloseGadgetList() 
EndProcedure 

Procedure SaveTable()   
EndProcedure 

Procedure LoadTable()  
EndProcedure 

Procedure Open_Window_0(YTableLineList.TableLine(),XTableColumnList.TableColumn(),G.gad()) 
  GWB.l=459:GWH.l=285
  If OpenWindow(#Window_0, 74, 19, GWB.l, GWH.l,"TableGadget" , #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar)   
    TableGadget(1,5,5,300,200,"Index",50,YTableLineList(),XTableColumnList(),G()) 
    AddTableColumn(1,0,"Bemerkung",100,     XTableColumnList(),G())  
    AddTableColumn(1,0,"NotizAnweisung",100,XTableColumnList(),G()) 
    AddTableColumn(1,0,"Bemerkung",100,     XTableColumnList(),G()) 
    AddTableColumn(1,0,"Bemerkung2",100,    XTableColumnList(),G()) 
   ; CallDebugger
    For xxx= 1 To 50 
      AddTableLine(1,YTableLineList(),XTableColumnList(),G()) 
    Next 
  EndIf 
EndProcedure 
;Du siehst die Listen sind nicht global trotzdem werden sie in den Unterprogrammen verwendet! 
NewList TableColumnList.TableColumn() 
NewList TableLineList.TableLine() 
NewList gadgets.gad()
Open_Window_0(TableLineList(),TableColumnList(),gadgets()) 

Repeat 
  Event = WaitWindowEvent()  
  EventType = EventType() 
  Select event ;EventType
  Case #PB_Event_Gadget
    GadgetID = EventGadget() 
    D=GetGadgetData(gadgetid)   
    SelectElement(gadgets(),D-1)
    Debug "("+Str(gadgets()\zeile)+","+Str(gadgets()\spalte)+")"
  Case #PB_Event_Repaint
    If IsWindow(0) :UpdateWindow_(WindowID(0)) :EndIf
    Debug "Repaint"
  Case #WM_SIZE
    nwh.l=WindowHeight(0) :nwb.l=WindowWidth(0)
    If nwh.l<>GWH.l Or  nwb.l<>GWB.l
      ResizeGadget(1, 5*nwb.l/GWB.l  ,  5*nwh.l/GWH.l, 300*nwb.l/GWB.l , 200*nwh.l/GWH.l)
      ForEach gadgets()
        With gadgets()
        EndWith      
      Next
      Debug "Size"
    EndIf 
  EndSelect
Until Event = #PB_Event_CloseWindow 
End 

Verfasst: 26.03.2006 16:49
von mk-soft
@in_go
Super beispiel :allright: :allright: :allright:

Darf nach man doch nutzen und weiterentwickeln?
Stelle gerade fest das ich mal die gesamte Befehles und Funktionsliste
mal durchschauen muss. Ist so viel GUTES dazugekommen, was man noch
gar nicht gesehen und ausprobiert hat.

FF :wink: