Sprache gesucht!



  • Da mir jedesmal wenn ich mit eigenen Überlegungen zu dem Thema angefangen hab Entgegnungen wie "gibts doch schon, wozu das Rad neu erfinden" gebracht wurden, auf der anderen Seite aber sämtliche Beispiele eine oder mehrere meiner Anforderungen nicht erfüllt haben hier eine Feature-Wishlist. (Dass die Anforderungen nicht erfüllt wurden liegt evtl daran dass ich sie nie alle genannt hab, was sich jetzt ändern soll).

    Ich suche also eine Sprache, die folgendes erfüllt:

    - Objektorientiert
    - Imperativ
    - (statisch) Typsicher
    - (wichtigstes) Zur Laufzeit modifizierbare Klassen und Objekte. Soll heißen, das laufende Programm soll durch eine neue Version desselben Programms ersetzt werden können, wobei sich sowohl Klassen als auch die zugehörigen Objekte beim Versionswechsel ändern. Das Feature soll zum natürlichen Sprachumfang gehören.

    zur Motivation habe ich bereits in einem anderen Thread etwas geschrieben: http://www.c-plusplus.net/forum/viewtopic-var-t-is-221838-and-start-is-4.html

    Die ersten beiden Anforderungen ergeben sich aus der Tatsache, dass die Sprache auch für weniger geübte Programmierer leicht erlernbar sein soll und erfahrungsgemäß heutige Programmieranfänger weder mit rein prozeduralen Sprachen noch mit deklarativen Sprachen viel anfangen können. Die dritte Anforderung (Typsicherheit) beruht auf Sicherheitsüberlegungen sowie auf Bequemlichkeit und persönlicher Präferenz.

    Folgende bereits vorgeschlagene Sprachen fallen daher aus:
    Common Lisp (funktionale Sprache)
    Ruby, PhP (dynamisch typisiert)
    Erlang (nicht objektorientiert, nicht typsicher)
    in C++, Java etc ist sowas grundsätzlich mit viel Aufwand möglich, um den Aufwand zu reduzieren war meine Überlegung, eine eigene (an Java/C++ angelehnte?) Sprache zu entwickeln um dem Entwickler den Aufwand aus der Hand zu nehmen, da es sich ja um eine immer wiederkehrende Aufgabe handelt.

    Gibts eine Sprache die die Anforderungen schon von sich aus erfüllt oder sollte ich mir das doch zusammenbasteln?



  • Hast du dich schon mal in der .NET Ecke umgesehen?



  • Groovy ist (auch) statisch typisiert, an Java angelehnt und läuft auf der JVM.
    Scala ist statisch typisiert, OO und funktional.
    In wie weit diese Sprachen Punkt 4 erfüllen weiß ich nicht.

    Ich empfehle, Punkt 3 über Bord zu werfen und es einfach mal dynamisch zu versuchen. Es ist nicht unsicherer (wenn man gut testet), auf jeden Fall bequemer als ein statisches System und persönliche Präferenzen ändern sich zuweilen 🙂



  • danke schonmal für die Beiträge, vor allem tfa's Tip mit Groovy hat mich auf Grails gebracht, werd mir das mal näher anschauen.

    Sollte sich das als annehmbare Sprache für meine Zwecke erweisen werd ich das Vorhaben mit der eigenen Sprache nicht auf Eis legen sondern es sogar noch erweitern - statt irgendeinen Wrapper/Generator für C++-DLLs o.ä. zu schreiben kann ich dann tatsächlich komplett n eigenen Compiler anfangen, nur ums mal gemacht zu haben - es muss ja nicht fertig werden und 100%ig laufen 😉



  • statisch typisiert und zur laufzeit klassen ändern beisst sich.

    wenn ich

    obj.meth();

    mache und das statisch auswerten will, dann kann ich nicht garantieren dass obj zu diesem zeitpunkt meth als member haben wird. man muss also wenn du statisch typisierst das typsystem erstmal umgehen um sowas zu ermöglichen...

    deshalb: die antwort heisst vermutlich
    perl, php, python, ruby,...



  • Groovy, Ruby und Phyton haben eine dynamische Typisierung sind aber Type-Safe. Ledenfalls lt. http://de.wikipedia.org/wiki/Dynamische_Typisierung
    In Groovy wird eine Exception geschmissen, wenn du versucht eine Integer-Variable einen StringLiteral zu geben.



  • Common Lisp ist OO (war sogar die erste OO Sprache, die standardisiert wurde!) und bietet einem auch an Typen statisch festzulegen. Aber ganz ehrlich: Statische Typisierung und dynamische OO beißen sich einfach. Wie Shade schon erklärt hat.



  • Zeus schrieb:

    Groovy, Ruby und Phyton haben eine dynamische Typisierung sind aber Type-Safe. Ledenfalls lt. http://de.wikipedia.org/wiki/Dynamische_Typisierung
    In Groovy wird eine Exception geschmissen, wenn du versucht eine Integer-Variable einen StringLiteral zu geben.

    Wobei bei Ruby nicht die Variable getypt wird, sondern das referenzierte Objekt. Bei Python wird jedoch die Variable getypt.
    Das heißt bei Ruby kann eine Variable einmal einen String enthalten, dann eine Zahl und dann wieder einen String.
    Bei Pyhton bedeutet einmal String immer String.

    Und das finde ich imo besser und auch sehr schade, dass es Ruby nicht so macht.



  • Tippgeber schrieb:

    Wobei bei Ruby nicht die Variable getypt wird, sondern das referenzierte Objekt. Bei Python wird jedoch die Variable getypt.
    Das heißt bei Ruby kann eine Variable einmal einen String enthalten, dann eine Zahl und dann wieder einen String.
    Bei Pyhton bedeutet einmal String immer String.

    Und das finde ich imo besser und auch sehr schade, dass es Ruby nicht so macht.

    Das ist komplett falsch. Variablen in Python können immer beliebige Objekte aufnehmen - auch von wechselnden Typen, ganz genau wie in Ruby.



  • tfa schrieb:

    Tippgeber schrieb:

    Wobei bei Ruby nicht die Variable getypt wird, sondern das referenzierte Objekt. Bei Python wird jedoch die Variable getypt.
    Das heißt bei Ruby kann eine Variable einmal einen String enthalten, dann eine Zahl und dann wieder einen String.
    Bei Pyhton bedeutet einmal String immer String.

    Und das finde ich imo besser und auch sehr schade, dass es Ruby nicht so macht.

    Das ist komplett falsch. Variablen in Python können immer beliebige Objekte aufnehmen - auch von wechselnden Typen, ganz genau wie in Ruby.

    Seit wann das? Aber ich habe gerade nachgesehen und du hast recht. Ich bin mir so sicher, dass ich das damals in Dive into Python gelesen habe. Und habe es seither auch nie mehr ausprobiert.



  • Keine Ahnung. War das je anders?



  • Ich bin bei Python seit dem 20.01.06 und damals wars auch schon so. 😉



  • Shade Of Mine schrieb:

    statisch typisiert und zur laufzeit klassen ändern beisst sich.

    wenn ich

    obj.meth();

    mache und das statisch auswerten will, dann kann ich nicht garantieren dass obj zu diesem zeitpunkt meth als member haben wird.

    Doch, kann ich und will ich. Wenn ich obj.meth() aufrufen will, muss zu dem Zeitpunkt meth() ein member von obj sein. Wenn ich auf der anderen Seite die Klasse von obj später so ändern will, dass meth() aus der Klasse entfernt wird, darf gleichzeitig im restlichen Code kein Aufruf von meth() mehr vorhanden sein. Dass dadurch neuer Code erstmal umfangreich auf Konsistenz gecheckt werden muss nehme ich in Kauf, wenn ich dadurch verhindere dass mein System mir um die Ohren fliegt weil ich in einer dynamisch typisierten Sprache irgendwo ein meth() im Code gelassen hab obwohl obj neuerdings diese Methode garnicht mehr hat. Wenn ich auf der anderen Seite die Sicherheit haben will dass mir der Code nicht um die Ohren fliegt, muss ich eine Möglichkeit haben, ihn beim "einchecken" zu prüfen, und das geht nur mit statischer Typisierung.



  • Also stell dir mal vor du kapselst die Anweisungen, die die Struktur eine beliebigen Klassen ändert. Dies kann dann vom Benutzer aktiviert werden. Wie soll der Compiler jetzt auf die Typen nachprüfen, wenn die Compilezeit schon längst um ist?



  • pumuckl schrieb:

    Doch, kann ich und will ich.

    Kannst du aber nicht mit statisch typisierten Sprachen.

    Dass ist der Sinn von statisch typisierten Systemen dass ich garantieren kann dass obj die methode meth hat oder nicht.
    Was du willst ist ein dynamisch typisiertes System wo du zur zeit des code erstellens nicht weisst ob obj jetzt die methode meth hat oder nicht.

    Wenn ich obj.meth() aufrufen will, muss zu dem Zeitpunkt meth() ein member von obj sein. Wenn ich auf der anderen Seite die Klasse von obj später so ändern will, dass meth() aus der Klasse entfernt wird, darf gleichzeitig im restlichen Code kein Aufruf von meth() mehr vorhanden sein. Dass dadurch neuer Code erstmal umfangreich auf Konsistenz gecheckt werden muss nehme ich in Kauf, wenn ich dadurch verhindere dass mein System mir um die Ohren fliegt weil ich in einer dynamisch typisierten Sprache irgendwo ein meth() im Code gelassen hab obwohl obj neuerdings diese Methode garnicht mehr hat.

    Klingt ziemlich doof. Du sagst nämlich effektiv: du willst kein dynamisches system sondern du willst immer alles komplett neu kompilieren. Wenn du meth raus nimmst muss der code ja umgeschrieben werden.

    Wenn ich auf der anderen Seite die Sicherheit haben will dass mir der Code nicht um die Ohren fliegt, muss ich eine Möglichkeit haben, ihn beim "einchecken" zu prüfen, und das geht nur mit statischer Typisierung.

    Du hast dynamische typisierung nicht verstanden.
    der code fliegt dir so oder so um die ohren wenn er falsch ist.

    die frage: was willst du wirklich. aktuell beschreibst du ein system dass kein bisschen dynamisch ist. das kannst du ohne aufwand in c++ implementieren. du kompilierst bei jeder änderung alles neu und ersetzt dann auf einen schlag alle binaries.



  • Shade Of Mine schrieb:

    die frage: was willst du wirklich. aktuell beschreibst du ein system dass kein bisschen dynamisch ist. das kannst du ohne aufwand in c++ implementieren. du kompilierst bei jeder änderung alles neu und ersetzt dann auf einen schlag alle binaries.

    Nur dass ich dabei die Laufzeitumgebung inklusive aller bereits bestehenden Objekte verliere, was eben genau das ist was ich nicht will.

    Im Grunde könnte mans auch so beschreiben, dass ich das neue Programm kompiliere und sofort starte, und zwar mit der alten Laufzeit als Initialisierung. Das neue Programm transformiert dann die alten Objekte entsprechend der Vorgaben und arbeitet dann mit den neuen Objekten wie gehabt weiter.



  • pumuckl schrieb:

    Im Grunde könnte mans auch so beschreiben, dass ich das neue Programm kompiliere und sofort starte, und zwar mit der alten Laufzeit als Initialisierung. Das neue Programm transformiert dann die alten Objekte entsprechend der Vorgaben und arbeitet dann mit den neuen Objekten wie gehabt weiter.

    Denk mal nochmal nach.



  • Was du willst macht keinen Sinn. Genau für soetwas gibt es dynamische typisierung.

    Man könnte jetzt natürlich hergehen und einfach immer konverter schreiben um den aktuellen status zu behalten wenn man das system mit dem neuen code neustartet. mit serialisierungs-frameworks sollte das kein allzugroßes problem sein.

    aber du stößt an allen ecken und enden auf probleme die du nicht haben würdest wenn du zB python oder ruby verwenden würdest. dynamische typisierung ermöglicht ja genau das was du willst - code zur laufzeit zu ändern.

    zB hatte volkard als bot in #cpp eine lange zeit Marvin. Marvin war in Perl geschrieben und man konnte zur laufzeit allen möglichen code austauschen. Marvin hat sich nie vom server trennen müssen nur weil er upgedatet wurde.

    das ganze in statischen sprachen ist schon deutlich schwerer.
    wozu willst du statische typisierung haben?

    denn eigentlich sollte man das richtige tool für den richtigen job verwenden. aber gerade wenn du dynamisch code austauschen willst, dann stören statische typchecks nur. und es ist ja nicht so dass dynamische typisierung schwach wäre oder fehler provozieren würde. viele leute sehen dynamische typisierung als fehlerunfanfälliger an - wobei das immer eine endlose debatte ist bei der keiner gewinnen kann...



  • Wenn ich mir das so durchlese scheints das einfach nicht zu geben, und es scheint auch keiner meine Motivation einzusehen.

    Gerade wenn ich dynamisch Code austausche besteht doch die Gefahr dass ich höllisch aufpassen muss um nicht beispielsweise Aufrufe von nicht vorhandenen Methoden zu haben. Oder Zugriffe auf nichtmehr vorhandene Member. Im Grunde will ich doch nur das Beste aus beiden Welten - die Flexibilität durch dynamisch änderbaren Code und die Sicherheit und Konsistenz die mir der Compiler durch statische Typüberprüfung gewährleisten kann.

    Mir ist klar dass ich die Vielfalt der möglichen Änderungen dadurch einschränke, weil damit der Code nur von einem konsistenten Zustand in den nächsten übergehen kann ohne irgendwelche losen Enden, aber gerade das will ich ja erreichen.

    Wäre für einen solchen Zweck evtl folgendes sinnvoll?:
    - Ich erweitere eine dynamisch typisierte Sprache um Typbezeichner und alles weitere was ich für statische Typisierung/die Konsistenzchekcs brauche.
    - Ein Präprozessor (im Grunde schon ein halbes Compilerfrontend) übernimmt die Typüberprüfungen und weitere Konsistenzchecks, übersetzt den ganzen Mist in die eigentliche Sprache und macht den Codeupdate.



  • pumuckl schrieb:

    Gerade wenn ich dynamisch Code austausche besteht doch die Gefahr dass ich höllisch aufpassen muss um nicht beispielsweise Aufrufe von nicht vorhandenen Methoden zu haben. Oder Zugriffe auf nichtmehr vorhandene Member. Im Grunde will ich doch nur das Beste aus beiden Welten - die Flexibilität durch dynamisch änderbaren Code und die Sicherheit und Konsistenz die mir der Compiler durch statische Typüberprüfung gewährleisten kann.

    Du solltest dir erstmal die dynamischen Sprachen ansehen, bevor du irgendwas in dem Mund nehmst.

    class Auto
      def fahren()
        puts "Jetzt fahrt das Auto"
      end
    end
    
    class Flugzeug
      def fliegen()
        puts "Jetzt fliegt das Flugzeug"
      end
    end
    
    x = Auto.new
    x.fliegen;
    

    D:\workspace\RubyApplication2\lib\main.rb:18: undefined method `fliegen' for #Auto:0x1554d32 (NoMethodError)

    Ist übrigends kein Compilerfehlermeldung, sonder vom Interpreter.



  • naja, schau mal:

    ruby-progger ~ $ irb
    irb(main):001:0> class Test
    irb(main):002:1>   def foo()
    irb(main):003:2>     puts "In foo()."
    irb(main):004:2>   end
    irb(main):005:1> end
    => nil
    irb(main):006:0> t = Test.new
    => #<Test:0xb7c053fc>
    irb(main):007:0> t.foo
    In foo().
    => nil
    irb(main):008:0> class Test
    irb(main):009:1>   def bar()
    irb(main):010:2>     puts "In bar()."
    irb(main):011:2>   end
    irb(main):012:1> end
    => nil
    irb(main):013:0> t.bar
    In bar().
    => nil
    irb(main):014:0> def t.bar
    irb(main):015:1>   puts "t's own bar()"
    irb(main):016:1> end
    => nil
    irb(main):017:0> t.bar
    t's own bar()
    => nil
    irb(main):018:0> another_t = Test.new
    => #<Test:0xb7bd8870>
    irb(main):019:0> antother_t.bar
    NameError: undefined local variable or method `antother_t' for main:Object
            from (irb):19
            from :0
    irb(main):020:0> another_t.bar
    In bar().
    => nil
    irb(main):021:0>
    

Anmelden zum Antworten