static, Singleton, etc. verbieten?
-
Könnte man sich in einer neuen Programmiersprache (in erster Linie OOP, aber best practice sollte vorgehen) vorstellen diese Konstrukte auszumerzen?
Typische Einsatzzwecke (aus Java-Sicht, wird wohl in anderen Programmiersprachen anders aussehen)
- static - Math.sin()
- static - globaler counter über alle objekte hinweg
- static - Utilities
- singleton - Printer manager
- singleton - Command line I/O
1) Use case: Sinus von einer Zahl berechnen (berechnen ist leider sehr prozedural wie ich finde...) angle <- 90 Degree sinus <- sinus(angle)
Wohin also nun mit dem Sinus? Ich sende dem Winkel die Nachricht "berechne mir mal deinen Sinus". Das sieht aber nur solange gut aus bis es an die Implementierung des Sinus geht. "as Degree" deutet schon hin, dass ein Degree wissen müsste wie er seinen Sinus berechnet, ich glaube er sollte das nur weiterdelegieren (und sich vorher wohl in Radiant umrechnen):
Degree { state { Decimal degrees; } on construction ( Decimal degrees ) { this.degrees = degrees; } on sinus { // hier die impl? } } // sieht ohnehin furchtbar aus, also besser: // ich mag irgendwie das konzept, dass es grundsätzlich nur Interfaces gibt // Degree ist wie ein Decimal, können aber nicht direkt zugewiesen werden // "90 Degree" ist eine Literal-Kurzfrom für "new Degree(90)", keine ahnung noch ob das gut ist Degree like Decimal { on sinus () { // hier die impl? } }
Globaler Counter sollte doch besser so sein:
MyFactory { state { counter : Number from 0 to inf } on construction () { counter <- 0 } on createStuff ( ) returns MyStuff { counter++; return new MyStuff() notificate on destruction as deleteStuff; } on deleteStuff ( ) { counter--; } }
Wobei jetzt getCounter() ja übel ist ... das ist nicht ganz so OOP denke ich.
- Jetzt wirds haarig, meistens braucht man die ja immer wenn ein Typ was nicht kann was man jetzt aber nötig hätte.
Da es eh über das public interface geht könnte ich mir vorstellen einfach die Methoden erweiterbar zu machen:
MyFoo { on bar ( var : String ) { uses Somewhere; var <- trim(var); // do something with trimmed var } } Somewhere extends String { on trim ( ) returns String { // hier trimmen, } }
Irgendwie kommt da nicht einmal der Hauch eines static-Bedürfnisses auf.
- Singletons brauchen static, nicht immer, aber eigentlich ist es zumindest in Java so sehr schön. Entweder ich unterstütze das direkt in der Sprache:
singleton MyFoo { on construction () /* wird nur beim ersten mal aufgerufen */ { ... } } singleton MyFoo2 { on init ( i : Number ) { ... } /* special method ?! */ } MyBar { on something () { var <- MyFoo; var <- MyFoo2; // exception init(MyFoo2, 5); var <- MyFoo2; } }
Aber wo benötige ich denn überhaupt Singletons? Beispiel: "Hello World" ausgeben...
module com.sidewinder.mysample; uses std.ui.cli.Out; MyApp implements Application // Application.run ist quasi main in Java { on run ( ) { // Out ist natürlich ein IrgendwasWriter, aber das verschiebt das Problem nur write(Out, "Hello, World!") /?? } } // in dem fall könnte die Application eine anbindung haben: write("Hello, World!") // implizites write(this/super, "Hello, World!")
Gibt es nötige Singletons die nichts mit einer Anbindung an die Außenwelt zu tun haben die quasi von der VM vorgegebn werden könnte?
MfG SideWinder
-
Edit: Ziemlich viel Blubba ist da jetzt zusammengekommen, vielleicht nicht einmal alles ganz logisch und zusammenhängend, aber die Ideen kommen leider nicht straight
Hoffe trotzdem, dass der Thread etwas Interesse findet
MfG SideWinder
-
Wie machst du Math.PI? Oder Math.Random()?
-
SeppJ schrieb:
Wie machst du Math.PI? Oder Math.Random()?
Das ist leicht. PI gehört wie sin und sqrt in die Klasse double und Random ist eine eigene Klasse.
-
Scala hat object also garantierte Singletons in der Sprache eingebaut, sieht recht nett aus und macht static relativ überflüssig, sowie Enums.
-
volkard schrieb:
SeppJ schrieb:
Wie machst du Math.PI? Oder Math.Random()?
Das ist leicht. PI gehört wie sin und sqrt in die Klasse double und Random ist eine eigene Klasse.
Nun kannst du aber nicht an alle mathematischen Funktionen denken die für double möglich sein sollen, wie tust du nun mit weiteren "Utility"-Funktionen?
expansion for Number // geht dann auch alle für like Number { on abs () { if(this >= 0) return this; return -this; } }
Ist nun aber nicht viel besser als irgendeine statische Sache. Ableiten? Nein...
Gesucht: Lokale Erweiterung eines Interfaces?!
MfG SideWinder
-
volkard schrieb:
SeppJ schrieb:
Wie machst du Math.PI? Oder Math.Random()?
Das ist leicht. PI gehört wie sin und sqrt in die Klasse double und Random ist eine eigene Klasse.
Also so?
class (Fractional a) => Floating a where pi :: a sqrt :: a -> a sin :: a -> a ... instance Floating Float instance Floating Double class Random a where random :: (RandomGen g) => g -> (a, g) ...
-
Oder so XD?
class MyDouble { } static class MyDoubleExention { static MyDouble pi(this MyDouble arg) { } }
-
SideWinder schrieb:
expansion for Number // geht dann auch alle für like Number { on abs () { if(this >= 0) return this; return -this; } }
Meinst du sowas?
abs n = if n < 0 then -n else n
Das geht dann für alle
n
in den TypklassenNum
(für-
) undOrd
(für<
). Man könnte auch schreiben:abs :: (Num a, Ord a) => a -> a abs n = if n < 0 then -n else n
Zeus schrieb:
Oder so XD?
class MyDouble { } static class MyDoubleExention { static MyDouble pi(this MyDouble arg) { } }
Ich dachte genau das will Side vermeiden.
-
@Zeus: Wir wollen ja static vermeiden und schönes OOP machen. Also quasi die ursprüngliche Klasse erweitern um diese Methode, ohne aber abzuleiten. Einfach annehmen, dass die ursprüngliche Implementierung nicht unbedingt vollständig gewesen ist. Man muss dann eben mit dem public interface leben.
MfG SideWinder
-
SideWinder schrieb:
@Zeus: Wir wollen ja static vermeiden und schönes OOP machen. Also quasi die ursprüngliche Klasse erweitern um diese Methode, ohne aber abzuleiten. Einfach annehmen, dass die ursprüngliche Implementierung nicht unbedingt vollständig gewesen ist. Man muss dann eben mit dem public interface leben.
MfG SideWinder
Tut es doch! Das static ist eher im Sinne zur Compilerzeit aufgelöst.
Die Extension kann ja in ein ganz anderes Namespace liegen, aber soweit ich sie einbinden kann ich von mein MyDouble-Instanz einfach zahl.pi() aufrufen. Die Extension hat auch kein Zugriff auf die private Felder.
-
Wozu willst du alles an ein Objekt hängen und warum soll das schönes OOP sein? Singleton sollte man vermeiden, vorallem, wenn sie nur Ersatz für globale Variablen sind und überall Abhängigkeiten erzeugen. Aber wieso sollte man Sinus krampfhaft an ein Objekt hängen wollen? Sinus ist doch keine Methode von Zahl. Sinus ist eine Funktion. Was soll da rauskommen? 3.sinus() ändert dann den Wert von 3 und es gibt keine 3 mehr im Programm?
-
Warum nicht?
var x = (3.0).sinus()
Es ist sinnvoll Type schmal zu halten. Aber es ist auch sinnvoll Extension anzuhängen.
-
Weil Sinus eine Funktion ist.
-
Man muss nicht alles von seiner natürlichen Definition wegreißen und irgendwie verobjektifizieren.
-
Man kann sich bis ins tausendste hineintheoretisieren in so höhere Programierspracheneinzelheiten,...man könnte stattdessen die Zeit nutzen, um die eigende Bibliothek mit ein paar selbstgeschriebenen Assemblerroutinen zu bereichern...das schützt glaube ich auch ein wenig...;)
-
Lallenbubbler schrieb:
Wozu willst du alles an ein Objekt hängen und warum soll das schönes OOP sein? Singleton sollte man vermeiden, vorallem, wenn sie nur Ersatz für globale Variablen sind und überall Abhängigkeiten erzeugen. Aber wieso sollte man Sinus krampfhaft an ein Objekt hängen wollen? Sinus ist doch keine Methode von Zahl. Sinus ist eine Funktion. Was soll da rauskommen? 3.sinus() ändert dann den Wert von 3 und es gibt keine 3 mehr im Programm?
Weil es in der OOP nur Objekte bzw. Klassen gibt? Nicht, dass reine OOP unbedingt die schönste Form der Programmierung ist, aber das Sinus eine Funktion ist, schadet ja nicht diese an Zahl anzuhängen. Für andere Objekte ist der Sinus evtl. etwas anderes. Und klarerweise ist 3 immutable und sinus liefert den Wert zurück.
@Zeus: Dieses Expansion-Konzept ist evtl. gut, siehe auch mein erstes Posting, vielleicht von der Syntax so:
expansion for Number { on sin () -> (Number) { // impl return result; } }
MfG SideWinder
-
Aus Neugier, wie kommst du dazu Sprachelemente auszudenken? ^^
-
Zeus schrieb:
Aus Neugier, wie kommst du dazu Sprachelemente auszudenken? ^^
Ich lerne gerade viel im Bereich Java Enterprise, derzeit versuche ich mich im Bereich JPA/Hibernate mit dem Spring Framework und Spring MVC mit Spring Security. Dabei fällt mir auf, dass Java mich manchmal zu Dingen zwingt die mich lange zum Nachdenken bringen wie es denn nun am Besten ist nur um dann draufzukommen, dass es schlicht und ergreifend an der Sprache selbst liegt.
Seit heute Nachmittag überlege ich ob es überhaupt besser möglich wäre
MfG SideWinder
-
Lallenbubbler schrieb:
Aber wieso sollte man Sinus krampfhaft an ein Objekt hängen wollen? Sinus ist doch keine Methode von Zahl. Sinus ist eine Funktion. Was soll da rauskommen? 3.sinus() ändert dann den Wert von 3 und es gibt keine 3 mehr im Programm?
Also ich hätte schon Interesse daran, es in einer Richtung zu vereinfachen.
Baum b; cout<<b.masse()<<'\n'; double d; cout<<d.sqrt()<<'\n';
oder
double d; cout<<sqrt(d)<<'\n'; Baum b; cout<<masse(b);
Aber auf keinen Fall das:
Baum b; cout<<Botanik.masse(b)<<'\n'; double d; cout<<Math.sqrt(d)<<'\n';//Hä? Was soll das denn?