Seite 2 von 2

Re: Funktion verändert input-argument, ohne dass sie es soll

Verfasst: Dienstag 19. Februar 2019, 22:37
von kbr
@Perlchamp: Genau. Bei mutablen Objekten in kopierten Datenstrukturen musst Du aufpassen. Gleiches gilt für Parameterübergaben. Bei nicht mutablen Objekten ist das unkritisch, da hier bei Änderungen stets ein neues Objekt als Resultat erzeugt wird. In Python wird alles per Referenz angesprochen, der Typ ist an das Objekt gebunden. Daher ist die Sprache sowohl dynamisch, als auch stark typisiert ("späte Typbindung"). Das ist für Umsteiger von statisch typisierten Sprachen oft etwas unheimlich. Ich empfinde dies mittlerweile als großen Vorteil und betrachte die type-annotations mit entsprechendem Argwohn. (Insbesondere die neuen Dataclasses, die type-annotations zwingend voraussetzen, gefallen mir überhaupt nicht. Aber da gehen die Meinungen sehr auseinander.)

Re: Funktion verändert input-argument, ohne dass sie es soll

Verfasst: Dienstag 19. Februar 2019, 23:00
von Perlchamp
@ _blackjack_ :
klar, wenn man weiß, was man will und vor allem, wenn man weiß, was das Programm tut und bei einer gewissenhaften Vorbereitung (OOA, OOE, OOD, OOP) muß man nicht mit Kanonen auif Spatzen schießen. Sooooo weit bin ich noch laaaaange nicht. Es ging mir bloß ums Verständnis und um's "sicher gehen" ...

@ kbr :
ja, dass der Typ an das Objekt gebunden ist, empfinde ich persönlich auch als sehr gutes "feature" und vor allen Dingen als sehr *entspannend* ...

Re: Funktion verändert input-argument, ohne dass sie es soll

Verfasst: Mittwoch 20. Februar 2019, 08:05
von Sirius3
@Perlchamp: auch das flache Kopieren einer Liste ist eher selten, denn man macht meist einfach eine neue veränderte Liste, statt eine bestehende zu verändern.
Häufiger ist, dass man irgend ein iterierbares Objekt hat und daraus eine Liste machen will, da funktioniert dann nur die Variante `list(iterable)`.

Re: Funktion verändert input-argument, ohne dass sie es soll

Verfasst: Mittwoch 20. Februar 2019, 23:35
von Perlchamp
@sirius3 :
... um es dann *beispielsweise* manipulieren zu können ...

Code: Alles auswählen

>>> list (“Buchstaben“)
[‘B‘, ‘u‘, ‘c‘, ‘h‘, ‘s‘, ‘t‘, ‘a‘, ‘b‘, ‘e‘, ‘n‘]

Re: Funktion verändert input-argument, ohne dass sie es soll

Verfasst: Sonntag 24. Februar 2019, 11:44
von __blackjack__
Okay, wir sind immer noch in den 80ern aber jetzt auf dem PC – das CBM BASIC-Programm nach GW-BASIC portiert das bis MS-DOS 4 als Programmiersprache dabei war. Die speziellen Kommentare für den Basic-Boss-Compiler sind weg, dafür sind alle Integer-Variablen jetzt entsprechend mit dem % benannt um sie zu Integer-Variablen zu machen. GW-BASIC kennt Befehle für Grafik und um einzelne Zeichen abzufragen, deshalb muss nicht mehr mit PEEK/POKE/WAIT direkt auf Speicher und Hardware zugegriffen werden. IF/THEN kennt nun auch ein ELSE. Und der SWAP-Befehl macht die entsprechende Subroutine überflüssig.

Code: Alles auswählen

100 RANDOMIZE -TIMER:SL%=640:SC%=350:DP=.3:MV%=5:A%=1:CD=.35
105 DIM CP%(SL%),CV%(SL%)
110 PRINT"Create and place cars...":GOSUB 5000:SCREEN 9
200 FOR Y%=0 TO SC%-1:GOSUB 500:GOSUB 1000:NEXT
210 WHILE INKEY$="":WEND:GOTO 200
500 ' ******************************
510 ' One simulation step.
520 '
530 ' 1. Update velocities.
540 FOR I%=0 TO CC%:IF I%=CC% THEN J%=0 ELSE J%=I%+1
550 V%=CV%(I%)+A%:D%=CP%(J%)-CP%(I%)-1:IF D%<0 THEN D%=D%+SL%
560 IF V%>D% THEN V%=D%
570 IF V%>MV% THEN V%=MV%
580 IF V%>=1 THEN V%=V%+(RND(1)<DP)
590 CV%(I%)=V%:NEXT
700 ' 2. Update positions.
710 FOR I%=0 TO CC%:CP%(I%)=(CP%(I%)+CV%(I%)) MOD SL%:NEXT:RETURN
1000 ' ******************************
1010 ' Plot row.
1020 '
1030 LINE (0,Y%)-(SL%,Y%):FOR I%=0 TO CC%:PRESET (CP%(I%),Y%):NEXT:RETURN
5000 ' ******************************
5010 ' Create cars.
5020 '
5030 CC%=INT(SL%*CD)-1:FOR I%=0 TO SL%-1:CP%(I%)=I%:NEXT
5040 FOR I%=0 TO SL%-1:J%=INT(RND(1)*(SL%-I%))+I%:SWAP CP%(I%),CP%(J%):NEXT
5050 F%=0:FOR I%=0 TO CC%-1:J%=I%+1
5055 IF CP%(I%)>CP%(J%) THEN F%=-1:SWAP CP%(I%),CP%(J%)
5060 NEXT:IF F% THEN 5050
5070 RETURN
Eigentlich hätte man hier auch schon was mit den Variablennamen machen können, weil GW-BASIC mehr als zwei Zeichen erlaubt. Aber da GW-BASIC Programme oft von anderen Systemen portiert waren (wie in diesem Fall) oder dorthin portiert werden sollten, war es nicht unüblich die zwei Zeichen Grenze nicht zu überschreiten. Zudem sind nur Grossbuchstaben möglich was sich Variablennamen die aus mehr als einem Wort zusammengesetzt sind, unschön liest. Und es wird schwieriger Anweisungen und Funktionen von Variablen zu unterscheiden. Man hat bei GW-BASIC ja kein Syntaxhighlighting wie hier im Forum.

Edit: Doch mal mit längeren Namen:

Code: Alles auswählen

100 RANDOMIZE -TIMER:STREET.LEN%=640:STEPCOUNT%=350:CAR.DENSITY=.35:MAX.V%=5
105 ACCEL%=1:DECEL.PROB=.3:DIM CAR.POS%(STREET.LEN%-1),CAR.V%(STREET.LEN%-1)
110 PRINT"Create and place cars...":GOSUB 5000:SCREEN 9
200 FOR Y%=0 TO STEPCOUNT%-1:GOSUB 500:GOSUB 1000:NEXT
210 WHILE INKEY$="":WEND:GOTO 200
500 ' ******************************
510 ' One simulation step.
520 '
530 ' 1. Update velocities.
540 FOR I%=0 TO CC%:IF I%=CC% THEN J%=0 ELSE J%=I%+1
550 V%=CAR.V%(I%)+ACCEL%:D%=CAR.POS%(J%)-CAR.POS%(I%)-1
555 IF D%<0 THEN D%=D%+STREET.LEN%
560 IF V%>D% THEN V%=D%
570 IF V%>MAX.V% THEN V%=MAX.V%
580 IF V%>=1 THEN V%=V%+(RND(1)<DECEL.PROB)
590 CAR.V%(I%)=V%:NEXT
700 ' 2. Update positions.
710 FOR I%=0 TO CC%
715 CAR.POS%(I%)=(CAR.POS%(I%)+CAR.V%(I%)) MOD STREET.LEN%:NEXT:RETURN
1000 ' ******************************
1010 ' Plot row.
1020 '
1030 LINE (0,Y%)-(STREET.LEN%,Y%):FOR I%=0 TO CC%
1035 PRESET (CAR.POS%(I%),Y%):NEXT:RETURN
5000 ' ******************************
5010 ' Create cars.
5020 '
5030 CC%=INT(STREET.LEN%*CAR.DENSITY)-1
5035 FOR I%=0 TO STREET.LEN%-1:CAR.POS%(I%)=I%:NEXT
5040 FOR I%=0 TO STREET.LEN%-1:J%=INT(RND(1)*(STREET.LEN%-I%))+I%
5045 SWAP CAR.POS%(I%),CAR.POS%(J%):NEXT
5050 F%=0:FOR I%=0 TO CC%-1:J%=I%+1
5055 IF CAR.POS%(I%)>CAR.POS%(J%) THEN F%=-1:SWAP CAR.POS%(I%),CAR.POS%(J%)
5060 NEXT:IF F% THEN 5050
5070 RETURN

Re: Funktion verändert input-argument, ohne dass sie es soll

Verfasst: Samstag 2. März 2019, 10:59
von __blackjack__
Dann kam mit MS-DOS 5 QBasic – Keine Zeilennummern mehr, und selbst die Sprungmarken durch die man sie ersetzen kann, braucht man nicht unbedingt, weil es Unterroutinen und Funktionen mit lokalen Variablen gibt. Variablennamen können Gross- und Kleinbuchstaben enthalten, auch wenn die nicht unterschieden werden. Aber man kann MixedCase schreiben und muss keine Punkte mehr verwenden um Worte zu trennen. Strukturierte Schleifen und IF/ELSE-Zweige die über mehr als eine Zeile gehen können. Und benutzerdefinierte zusammengesetzte Datentypen. Keine zwei Arrays mehr um die Autos zu beschreiben sondern nur noch eines bei dem jeder Eintrag ein Auto mit seinen zwei Eigenschaften beschreibt.

Code: Alles auswählen

CONST StreetLength = 640, StepCount = 480
CONST CarDensity = .35
CONST Acceleration = 1, MaxVelocity = 5, DecelerationProbability = .3

TYPE TCar
  Position AS INTEGER
  Velocity AS INTEGER
END TYPE

DIM i AS INTEGER
REDIM Car(0) AS TCar

RANDOMIZE -TIMER
PRINT "Create and place cars..."
CreateCars Car()
SCREEN 11
DO
  FOR i = 0 TO StepCount - 1
    SimulationStep Car()
    PlotRow i, Car()
    IF INKEY$ = CHR$(27) THEN EXIT DO
  NEXT
  SLEEP
LOOP UNTIL INKEY$ = CHR$(27)

SUB CreateCars (Car() AS TCar)
  DIM i AS INTEGER, NewCar(StreetLength - 1) AS TCar
  InitCars NewCar()
  ShuffleCars NewCar()
  REDIM Car(INT(StreetLength * CarDensity) - 1)
  FOR i = 0 TO UBOUND(Car)
    Car(i) = NewCar(i)
  NEXT
  SortCars Car()
END SUB

SUB InitCars (Car() AS TCar)
  DIM i AS INTEGER
  FOR i = 0 TO UBOUND(Car)
    Car(i).Position = i
    Car(i).Velocity = 0
  NEXT
END SUB

FUNCTION Min% (a AS INTEGER, b AS INTEGER)
  IF a < b THEN Min% = a ELSE Min% = b
END FUNCTION

SUB PlotRow (y AS INTEGER, Car() AS TCar) STATIC
  DIM i AS INTEGER
  LINE (0, y)-(StreetLength, y)
  FOR i = 0 TO UBOUND(Car)
    PRESET (Car(i).Position, y)
  NEXT
END SUB

SUB ShuffleCars (Car() AS TCar)
  DIM i AS INTEGER, j AS INTEGER
  FOR i = 0 TO UBOUND(Car)
    j = INT(RND(1) * (UBOUND(Car) + 1 - i)) + i
    SWAP Car(i), Car(j)
  NEXT
END SUB

SUB SimulationStep (Car() AS TCar) STATIC
  DIM i AS INTEGER, j AS INTEGER
  FOR i = 0 TO UBOUND(Car)
    IF i = UBOUND(Car) THEN j = 0 ELSE j = i + 1
    UpdateVelocity Car(i), Car(j)
  NEXT
  FOR i = 0 TO UBOUND(Car)
    Car(i).Position = (Car(i).Position + Car(i).Velocity) MOD StreetLength
  NEXT
END SUB

SUB SortCars (Car() AS TCar)
  DIM i AS INTEGER, j AS INTEGER, swapped AS INTEGER
  DO
    swapped = 0
    FOR i = 0 TO UBOUND(Car) - 1
      j = i + 1
      IF Car(i).Position > Car(j).Position THEN
        swapped = -1
        SWAP Car(i), Car(j)
      END IF
    NEXT
  LOOP WHILE swapped
END SUB

SUB UpdateVelocity (Car AS TCar, NextCar AS TCar) STATIC
  DIM Velocity AS INTEGER, Distance AS INTEGER
  Velocity = Car.Velocity + Acceleration
  Distance = NextCar.Position - Car.Position - 1
  IF Distance < 0 THEN Distance = Distance + StreetLength
  Velocity = Min(Min(Velocity, Distance), MaxVelocity)
  IF Velocity >= 1 THEN
    Velocity = Velocity + (RND(1) < DecelerationProbability)
  END IF
  Car.Velocity = Velocity
END SUB