No,Squeak je reimplementacia Smalltalk-u 80, ktory vznikol v roku 1980…
1.je starsi ako C#
Takze „basnicka“ otazka je, naco niekto robi C# ked mame Smalltalk – taky pekny, cisty, dynamicky(ziadne typy) objektovo orientovany jazyk (v podstate prvy!) :-)
v principe mierna nevyhoda Smalltalkov je troska slabsia integracia s OS, a so systemovymi oknami (ale zasa napr. Squeak – bezi nezmenana rovnaka grafika na vsetkych OS, kde je portnuta virtualna masina, „podobne“ ako AWT v Jave)
Vyhody:
vsetko je objekt! :-) – aj cisla
a napriklad na ratanie s cislami je to uplne super:
kym sa da, tak to pouziva efektivnu reprezentaciu (plus minus napr. obycajny integer), ale ked treba, tak vysledkom operacie integer*integer je zrazu „big integer“; a vy sa o to nemusite starat, ci tam nie je pretecenie alebo co.(robi transparentu konverziu medzi typmi cisel podla potrieb operacie, ale pri zachovani kompatibility)
Alebo este krajsie je to pri deleni: 1/100 sa nemusi reprezentovat ako 0.01 ale moze to byt fakt zlomok; takze ani pri mnohych operaciach sa nestraca presnost
Alebo dalsi oblubeny priklad:
ako vyratate faktorial vo vasom C#, ci Jave? V Smalltalku/Squeaku uplne lahko:
10000 factorial.
V podstate objektu „10000“ co je cislo, integer, sa „posle sprava“ factorial == zavolanie metody factorial. a on to v pohode vyrata…
Treba si pockat este na dalsie diely serialu a nedivat sa nato zaujato..
Kdyby jste napsal skutečné výhody, tak to beru. Ale to co jste napsal lze s pomocí dodatečných knihoven zvládnout i v C#, v C++ i v javě.
A množství dodatečných knihoven se do úplnosti jazyka nepočítá. Nezáleží totiž, zda knihovny jsou nebo nejsou standardem jazyka. Vždycky jsou to knihovny. Naopak mě dost vadí, že součastí jazyka je nějaká zpráva „faktorial“. Tam vůbec nemá co bejt. To je věc knihovny, tam to patří.
Ona to byla v zásadě reakce na původní post. Vykřik typu, hele, tenhle jazyk je lepší, protože tenhle kód musím v tomhle jazyce napsat a v jiném jazyce na to zavolám funkci.
A já jen reaguju, že buď si pisatel neuvědomuje, že nesrovnává jazyky ale vybavenost standardních knihoven, a nebo opravdu platí, že součástí jazyka XX je funkce YY jako buildin (tedy ne knihovna), a pak si o takovém jazyku myslím své.
Například v Pascalu funkce write(), která, díky tomu, že Pascal neumí variabilní počet parametrů je buildin.
Máte špatné pocity, alespoň co se C++ týče. Tedy jestli jste myslel, že nahradíte všechny floaty zlomkama, tak to samozřejmě nejde, ale otázkou je, kdo by to měl chtít. Pokud chci plovoucí čárku, použiji float, pokud zlomky, použiji třídu rational. Ta třída má přetížení všechny matematické operátory, takže se s tím pracuje stejně jako s čísly
Jan Vraný dělá svým studentům demo, při kterém udělá pár úprav ve třídě Point a celé prostředí se mu pod rukama pěkně přeskládá. Pak řekne studentům, že pokud mu to předvedou v Javě, dá jim zápočet i bez toho, aby se museli učit Smalltalk.
Ale vážně, existuje celá řada věcí, která se ve Smalltalku dělá podstatně snáze, než v Javě něbo C# (ty jazyky jsou samozřejmě turingovsky úplné).
Ve Smalltalku lze používat kontinuace, což je nedocenitelná věc, pokud např. píšete pořádný webový nebo simulační framework. Má bohatší a rychlejší práci s výjimkami. Má lepší práci s uzávěry.
C#: static void Main() { List<Action> actions = new List<Action>(); for (int counter = 0; counter < 10; counter++) { actions.Add(() => Console.WriteLine(counter)); } foreach (Action action in actions) { action(); } } Smalltalk: | actions | actions := (1 to: 10) collect: [:i | [ Transcript show: i; cr.] ]. actions do: [:action | action value ].
V Javě ani C# si nepřenesete rozladěný program na jiný počítač jiné platformy a tam nedoladíte. Samotné spuštění vývojového prostředí je ve Smalltalku bleskurychlé.
Ve Squeaku ve veškerý kód pod BSD-like licencí. Aplikace ve Smalltalku mohou mít vč. virtuálního stroje třeba 2MB (nejmenší image, co jsem viděl, měla 1337 bytů). Existuje několik aplikací v Apple AppStore napsaných ve Smalltalku, ale asi žádná napsaná v Javě nebo C#.
Mnohem snáze se píší unit testy (všechny testovací frameworky jako JUnit dokonce vycházejí z původní SUnit pro Smalltalk) a vůbec zvráceností, které Smalltalk umožňuje a Java nebo C# prakticky nikoliv, je celá řada.
To je pravda, stale me neprestava prekvapovat, ze cely Squeak se nastartuje za par sekund, zatimco na te same masine se treba Eclipse (coz je rekl bych zhruba srovnatelne _POCTEM_ funkci) a i jeho GUI je takove ucesanejsi a rychlejsi nez AWT (fuj) nebo Swing (no po tech letech vyvoje taky zadna slava).
Rikam si, jestli to neni tim, ze proste Javisti a C++ ari radi delaji x-vrstev ( a pouzivaji uzavrene frameworky), zatimco Smalltalkeri stavajici objekty proste zmeni, takze to ve vysledku je cele mensi a rychlejsi.
To asi těžko. O srovnatelnosti počtu funkcí bych pochyboval, že umíte odhadnout. Nelze zahrnovat jen funkce, které vy používáte. Jen se někdy podívejte, kolik pluginů Eclipse natahuje, a spoustu jich ani nebudete tušit k čemu jsou. Eclipse také při startu kompiluje třídy, dělá to tedy JVM, takže to může být pomalejší. Jinak samozřejmě do Eclipse nevidím, ale jako C++ x-vrstev nepoužívám, nevezmu z internetu kdejaký bastl o kterým nevím, kolik má vrstev. Ale autoři Eclipse to možná dělají jinak…
Není ono AWT jen nativní mapování objektů konkrétního OS? Co vim, tak ve Windows se to mapuje na standardní okna, zatímco Swing si to maluje sám.
No je pravda, ze Eclipse znam o dost lip nez Squeak, takze se to tezko odhaduje. Pluginy Eclipse natahuje jen ty, ktere skutecne pouzivam, to je docela malo (krome SVN pluginu v podstate nic dalsiho). A to, ze Eclipse neco pri startu kompiluje (?) je asi chyba v navrhu ne, tady ma Squeak se svym .image docela vyhodu a mozna proto je i jeho startup o dost rychlejsi?
AWT je skutecne mapovani nativnich widgetu (nazyvaji je „heavyweight“ zatimco ty vetsi a pomalejsi Javovske „lightweight“ :-), tj. na Windows je to WinAPI, na Unixech nejake Motif-like widgety, hlavne se vsak jedna o par typu widgetu, takze napriklad tree nebo neco podobneho tam nenajdete.
To je jen malá špička ledovce ;-) Nějaké příklady…
Všechny metody, které používají řetězec s daným podřetězcem (obdoba je už dávno součást IDE):
CompiledMethod allInstances select: [:method | method hasLiteralSuchThat: [:lit | lit isString and: [lit includesSubstring: ‚browse it‘ caseSensitive: true]]]
Všechny třídy s definovanou instanční proměnnou #sender
Smalltalk allClasses select: [:class | class instVarNames includes: #sender ]
Diky, mozna ze me bude taky heretik :-) V kazdem pripade uz se par mesicu divam po nejakem trosku jinem pristupu k tvorbe webovek nez jak se to dela u „enterprise“ aplikaci, rikam si ze je dobra konkurencni vyhoda mit v zaloze nejakou uplne odlisnou technologii. Takze jeste jednou diky, jdu studovat.
Dynamicky typovaný (lépe říci třídovaný, typy samozřejmě nezná), silně typovaný (třídovaný), primitivní syntax bez zbytečného balastu dovolující krátký, přehledný a rychle psatelný kód bez významových záludností, bez syntaktických konstruktů pro podmínky, iterace, výjimky, výborné využití lambda-kalkulu pro blocks, reflexivní, …
Kdyby měl navíc jen tu blbou jednoduchou syntax, tak je to bomba.
Ten problem naznaceny v linku, je mnohem obecnejsi a dotyka se prakticky vsech vetsich projektu, vcetne kernelu, GNOME/KDE, Javy atd. Nekde zustanou penize a sila na vynalozeni velkeho usili pro dalsi vyvoj, nekde uz ne. Ale to je zname, ze produktivita s rostoucim projektem dosti strme klesa, takze pridat i malinkatou funkcionalitu do velkych projektu je hodne drahe a pracne.
Oblíbeným omylem všech OOP nováčků je lpění na „posílání zpráv“. Poukazovat na to, že tamten jazyk posílá zprávy a jiný jazyk zprávy neposílá ale volá metody. A že tamten jazyk jen říká co by měl objekt udělat a ten druhý mu přímo nařizuje, co má udělat. Ale to jsou všechno pitomosti.
Posílání zpráv v OOP terminologii samozřejmě neříká, jak je to implementované. Zprávy lze posílat synchroně a asynchroně, přičemž to první připomíná spíš volání metod. Synchroně znamená, že objekt, který zaslal zprávu nemůže pokračovat ve vykonávání kódu, dokud neobdrží odpověď. Asynchroní zpráva odpověď nevyžaduje. Lze objektu přímo předat „program“, který vykonat, nebo příkaz. Příkaz může objekt pochopit jinak, než program. Voláním metody dáváme objektu „program“ jako zprávu, konkrétně v C++ adresu programu, který má objekt vykonat. Ale u virtuálních metod už tomu tak není, tam dáváme objektu příkaz formou indexu do tabulky vt. Takže i tady platí, že objekt může zprávu pochopit jinak, než bylo zadáno.
Pokud se v souvislosti s OOP mluví o smalltalku a upozorňuje se třeba na to, že OOP obecně nezná typy a že mohu poslat kterémukoliv objektu jakoukoliv zprávu atd, tak i tohle všechno zvládneme v jiných jazycích, akorát prostě ne přímo, ale pomocí prostředníka. V Javě například pomocí interfaců. V C++ kupodivu ještě lépe, i tady máme interfacy, ale můžeme si je vyvolávat pomocí jména (nebo GUID). A interface, pokud obsahuje jednu metody, jedná se vlastně o objekt zprávy. Ale metod může mít víc. Konečně, třeba takové COM+ a jeho metoda QueryInterface. Každému objektu můžete položit otázku, zda neumí nějaký interface a je to ekvivalentní jako když se objektu zeptám, zda zpracuje nějakou zprávu. A stejně jako v OOP jsou objekty netypové (nemají typ), tak i v COM+ vzásadě objekty nemají typ, jen nabízí různé interfacy, libovolného množství a složení.
Uznávám, že například jazyky typu smalltalk řeší tohle všechno jednodušeji a nenutí programátora vymýšlet „systémy“ nebo používat knihovny, aby dosáhl téhož. Ale je to určitá cena za svobodu. V některých jazycích máme víc svobody, ale víc práce. V jiných jazycích zvládneme totéž s desetinou úsilí… ale něco nás to bude stát.
>> Oblíbeným omylem všech OOP nováčků je lpění na „posílání zpráv“. Poukazovat na to, že tamten jazyk posílá zprávy a jiný jazyk zprávy neposílá ale volá metody. A že tamten jazyk jen říká co by měl objekt udělat a ten druhý mu přímo nařizuje, co má udělat. Ale to jsou všechno pitomosti.
V jakých jazycích se dá napsat třída, která má vložený objekt a jedinou metodu, která říká „všechny zprávy, které neumím zpracovat, předej vloženému objektu“?
V jakých jazycích se dá napsat konstruktor, který vrací instanci jiné třídy než které je konstruktorem?
Takové drobné pitomosti :)
Jistě, třeba ta druhá věc se dá obejít tím, že místo konstruktoru voláme metodu třídy, která vrací nově vytvořený objekt. Proč ne? Koneckonců plechovku můžeme taky otevřít buď otvírákem nebo sekerou ;)
Samozřejmě že to co popisujete jde. Třeba QueryInterface vám sice nesmí vrátit interface vnořeného objektu, protože to Microsoft tak chce, ale já mám systém, který tohle pravidlo nemá a tam to jde. Takže já se objektu zeptám, ať mi dá interface, který on neumí, ale který umí jeho vnořený objekt, a on mi předá interface vnořeného objektu. A tomu pak zavolam metodu. Přitom zprávou v tomto případě není volání metody, ale celý protokol včetně dotazu na zadaný interface (a pokud jsou interfaci identifikovány objektem, (typeinfo), pak je to to samé jako jméno zprávy … jméno zprávy == taky objekt)
Konstruktor v OOP? Jestli si myslíte, že v OOP někdo definoval C++ konstruktor, tak jste vedle. V OOP pokud vím jsou továrny. Řeknu jednomu objektu, aby vytvořil jiný objekt. To že v C++ jsou speciální funkcí _TŘÍDY_ konstruktor není nic jiného, než objekt, který je singletonem (třída) má metodu „vytvoř instanci třídy“ (objekt). To nevylučuje, aby měl tento objekt jinou metodu „vytvoř instanci jiné třídy“. Mimochodem, třídy nepatří do OOP. v OOP jsou jen objekty
Asi tak, plechovku otevřu sekerou jako otvírákem, ale otvírákem si nenasekám dříví. Ale sekerou teoreticky mohu ten otvírák vyrobit :-)
Reagoval jsem na „Poukazovat na to, že tamten jazyk posílá zprávy a jiný jazyk zprávy neposílá ale volá metody.“
Přesně takhle to totiž AFAIK je – některé rádobyobjektové jazyky jako třeba C++ volají funkce, přičemž skutečně objektové jazyky posílají zprávy – se kterými potom objekt může dělat, co uzná za vhodné.
První příklad byl na to, že „vnější objekt“ se může chovat jakkoli podle toho, co má za vnořený objekt. Nevím, jak by se tohle dalo v C++ ne-složitě udělat, rád se nechám poučit. Nedovedu si to dost dobře představit ani v Javě a C#, i když tam by to možná přes nějaké ty reflexe atd. nějakým krkolomným způsobem šlo.
Ad konstruktor – ano, skutečně objektové jazyky konstruktory nepotřebují, stačí metody třídy*. Jenže to se netýká ani C++, ani Javy, ani C#.
Jediný „skutečně objektový“ jazyk, který znám, který se docela používá, je Objective C.
Pokud si vytvoříte nad jakýmkoliv jazykem jakýkoliv systém, který je de facto vlastním jazykem s vlastními zákonitostmi, tak už to není původní jazyk. Ano – v C++ určitě jde naprogramovat Smalltalk. To jde i v assembleru, a přesto nikdo soudný nebude považovat assembler za objektový jazyk.
* Pokud se vám slovo „třída“ nelíbí, nahraďte si ji opisem „singleton objekt továrna“, já s dovolením raději budu psát „třída“, je to kratší
Až na to, že já OOP považuji za filozofii, vy to považujete za technické řešení. Zkuste se na to dívat jak na filozofii. Nebo třeba jako na návrhový vzor. Tam vůbec neřešíte, zda volání zprávy vypada jako
obj1 zprava obj2
nebo
obj1.getInterface<zprava>().send(obj2)
Zapisy jsou ekvivalentni (za předpokladu, že getInterface a send jsou nástroje pro zacílení a posílání zprávy).
OOP je filozofie, kterou lze aplikovat na jakýkoliv jazyk. Technické řešení je detail.
Z C++. Zprava je ve skutecnosti deklarovana jako:
class zprava: IInterface { public: virtual void send(IObject *) = 0; }; class IObject { public: virtual IInterface *getInterfacePtr(const std::typeinfo &tinfo) {return 0;} template<class Ifc> Ifc &getInterface() { IInterface *ptr = getInterfacePtr(typeid(Ifc)); if (ptr == 0) throw ... nejaka vyjimka ... return static_cast(ptr); } virtual IObject() {} };
Hlavní myšlenka je v tom, že všechny objekty podědí IObject a ta obsahuje funkci na hledani rozhrani. Pomoci getInterface se zeptam objektu, zda umi nejake rozhrani a pokud ano, zavolam na rozhrani funkci. Pokud ne, hodi to vyjimku. Virtualni funkce getInterface pak musi byt implementovana ve vsechn objektech, da se tam pouzit i dynamic_cast (v příkladu to nemám, bylo by to složitější) a objekt pak pouze implementuje tu funkci jen tam, kde docházi k předávání kompetencí.
Objekt pak může vypadat takto (pro řešení s dynamic_castem)
class MujObjekt: public IObject, public zprava1, public zprava2, public zprava3,.... {....};
nebo
class MujObjekt { public: IInterface *getInterfacePtr(const std::typeinfo &type) { if (type == typeid(zprava1) return &objektCoUmiZprava1; ... ... return 0; } };
>> Až na to, že já OOP považuji za filozofii, vy to považujete za technické řešení.
V žádném případě. Nepodsouvejte mi prosím něco, co jsem neřekl a co jste si jenom vydedukoval z toho, co jsem napsal.
OOP je samozřejmě „filosofie“ naprosto nezávislá na samotném jazyku. Jenže jazyk jednotlivé myšlenky oné filosofie buď PŘÍMO (!) podporuje, nebo je potřeba v onom jazyku napsat systém, který je de facto samostatným jazykem, ve kterém už ony myšlenky půjdou využít. Mezi námi prostými venkovany se tomu říká drbat se levou rukou za pravým uchem…
Příklad:
myšlenkou je multithreadové programování
Otázka: dá se v assembleru programovat multithreadově? Ano, dá, pokud používám nějaké knihovny. Samotný jazyk pro to ale žádné prostředky nemá. Zkráceně řečeno: assembler multithreadové programování PŘÍMO nepodporuje.
Oproti tomu Java multithreadové programování podporuje víc – už jen např. klíčovým slovem synchronized, které assembler nemá, ať se kdo chce třeba na hlavu staví.
Samozřejmě si v assembleru můžu napsat makra, která budou dělat v principu totéž jako javovské „synchronized“, ale to neznamená, že assembler podporuje multithreadové programování. Jak už jsem řekl: jistě si v assembleru můžu napsat SmallTalk. Stejně tak si ho můžu napsat třeba v C, Javascriptu nebo čemkoli, co je turingovsky úplné.
Jestliže někdo tvrdí, že z hlediska multithreadového programování jsou assembler, C, Java a Erlang totožné jazyky, protože ve všech lze psát v duchu multithreadové filosofie, tak mu na to nelze říct než: netvrdíš nic jiného, než že tyhle jazyky jsou turingovsky úplné.
Váš příklad s nadstavbou nad C++, která umí něco, co C++ neumí, je toho víc než jasným příkladem. Stejně tak např. GObject nedokazuje, že C je OOP jazyk.
Pokud se vám to nelíbí, tak si pojem „objektový jazyk“ úplně vymažte ze slovníku a říkejte jenom „objektové POUŽITÍ turingovsky úplného jazyka“. Ovšem až budete někomu tvrdit, že Brainfuck nebo lambda kalkul jsou objektové jazyky, můžete zůstat …mírně řečeno… nepochopen
Tohle vlákno vzniklo proto, že jsem jen upozorňoval, že velmi častou chybou začátečníků je, že něco považují za pravé OOP a něco za nepravé OOP. Většinou v roli prvního příkladu je smalltalk a v druhem buď C++ nebo JAVA. Nejčastějším argumentem je posílání zpráv. A jedním dechem uvádím, že je to pitomost, protože způsob posílání zpráv nedělá z jazyka pravý OOP jazyk, protože pravé OOP vlastně neexistuje.
Můžete to chápat i jako pokus o flame :-)
V zásadě ale trpíme všichni rozsahem definic. Co už je OOP jazy a co nikoliv? Co už je multithreadový jazyk a co už nikoliv. Předně si myslím, že JAVA není multithreadový jazyk ani proto, že podporuje synchronized. Multithreadový jazyk si představuji něco úplně jiného. A stejně tak OOP jazyk. Javu i C++ považuji za OOP jazyky už proto, že techniky a konstrukce, které se tam používají uznadňují implementovat OOP filozofii. Stejně tak smalltalk to usnadňuje, je objektový jazyk. Ale podobně se lze dívat i na python :-) Programátora nutí myslet objektově. A to je celé. Přesto stejně ve všech těchto jazycích lze programovat procedurálně (po staru). O tom, zda jsou objekty implementované jako místa v paměti, záznamy v tabulkách, a zda se zprávy posílají, volají se metody a jestli objekty mají nebo nemají přístupné atributy (a zda vůbec mají atributy).
Vždycky na jedné straně bude stát náročnost implementace a na druhé straně úplnost (nebo pohodlí) OOP modelu. A tyhle dvě věci jdou prostě proti sobě.
PS: V tomto ohledu mě dost mrzí vývoj některých běžných jazyků. Například v C++0× jsou některé věci dobré, ale chybí dodělání věcí, které souvisí s OOP, například třídní proměnné, základní typy jako objekty, atd. Java vyloženě trpí neexistencí destruktorů, jako přesné vymezení existence objektu (objekt existuje od teď … až do někdy).
PSS: Překvapuje mě, že úpravou jednoho jazyka vzniká jiný jazyk, podle Vašich slov. Jenže opět trpíme rozsahem definic. Co je jazyk a co už není? Patří do jazyku jeho standardní knihovna? Tohle je třeba spor… má být v C++ podpora multithreadingu? Nebo si vystačíme s knihovní funkcí? Já zvládnu z C++ udělat multithreadový jazyk pomocí své knihovny.
Když protlačím svou (výše uvedenou) úpravu jazyka do standardních knihoven, bude z toho jazyk s úlnějším OOP modelem? Jiný příklad. Má být v C++ zaveden GC? Já tvrdím že ne. Já zvládnu napsat GC v současném C++ a nepotřebuju žádnou buildin podporu. A vo tom to je. Potřebujeme jazyk na vyšší úrovni abstrakce, aby jsme ocenili úplný OOP model? Já ho nepotřebuju, ale chápu, že někdo bez toho nemůže v noci spát. Kolik ho to bude stát výkonu. Kolik zbytečného kódu se kvůli tomu napíše a v runtime vykoná?
Omyl. Žádný spor o definici přece mezi námi není. Vaši větu „velmi častou chybou začátečníků je, že něco považují za pravé OOP a něco za nepravé OOP“ si překládám jako „v každém jazyce se dá psát objektově“.
Čili žádnou (užší či širší) definici „OOP jazyka“ nepotřebujeme, protože všechny jazyky jsou turingovsky kompletní, takže co se týče expresivnosti ekvivalentní.
Čili vaše hrdé zvolání „já umím v C++ napsat posílání zpráv“ přebíjím svým zvoláním „já to umím i v Brainfucku!“
Tím je causa finita.
No tak za prvé, já nejsem matfyzák a za druhé, pokud někdo tvrdí, že větu
C++ je míň OOP než Smalltalk
může říct jen „začátečník“, pak jste to Vy, ne já. OOP-ekvivalentnost jazyků tvrdíte Vy, ne já.
Já naopak výše zmíněnou větu klidně vyřknu a chápu ji jako jiné vyjádření teze „SmallTalk PŘÍMO podporuje větší množinu myšlenek OOP než C++“.
No a? Ale o to přece vůbec nejde. Napadlo mne, že nejste matfyzák, protože byste neměl takový zmatek se slovem defince.
Obecně se neříká objektové jazyky, ale objektově ORIENTOVANÉ jazyky. Orientují se na objektové programování. Je mi srdečně jedno, jak moc úplný je OOP model který jazyk používý. Většina současných OOPL (Object Oriented Programming Languages) implementují naprostou většinu z filozofie OOP. Je na Vás, abyste si vybral, co Vám vyhovuje co do výkonu, či rychlosti vývoje.
Jen jsem chtěl podotknout, že způsob komunikace mezi objekty nic neříká o úplnosti modelu OOP. V naprostý většina totiž volání metod vystačuje, a jen puntíčkář bude zkoumat technické pozadí implementace dívat se, zda zápis 100 factorial v nějakém bufferu vytvoří zprávu, kterou pak předá do jiného buffer a následně předá řízení oslovenému objektu, který jí z bufferu vyzvedne a provede … a bude tomu říkat zasílání zpráv.
>> Napadlo mne, že nejste matfyzák, protože byste neměl takový zmatek se slovem defince.
Nemám žádný zmatek se slovem „definice“. Říkám ale, že vy žádnou takovou definici nepotřebujete, protože se snažíte dokázat, že v každém jazyku se dá programovat podle OOP filosofie a že i když C++ nějaký OOP prvek neobsahuje, dá se tam nějak krkolomně nabastlit.
>> Obecně se neříká objektové jazyky, ale objektově ORIENTOVANÉ jazyky.
Toho slovíčkaření už bylo dost se slovem „třída“, ne?
>> Většina současných OOPL (Object Oriented Programming Languages) implementují naprostou většinu z filozofie OOP.
Opakuju: jediný běžně používáný jazyk, který znám a který implementuje přímo, čistě a jednoduše „naprostou většinu z filozofie OOP“, je Objective C. To není žýdný flame, to je konstatování.
Dal jsem vám jasný příklad s konstruktorem – v článku pod kterým diskutujeme, je uvedeno, k čemu je dobré, aby třída vracela instanci jiné třídy. Je to čisté, praktické a elegantní – a v současných OOP jazycích (Java, C#) to (čistě) nejde.
>> Jen jsem chtěl podotknout, že způsob komunikace mezi objekty nic neříká o úplnosti modelu OOP. V naprostý většina totiž volání metod vystačuje
No a s tím právě nesouhlasím – a klidně si mě nazývejte začátečníkem, to je mi celkem fuk.
Jestliže jazyk implementuje komunikaci mezi objekty blbě, naučí se programátor používat blbé postupy, které mají s OOP málo společného. Viz výměna názorů mezi p. Viriusem a p. Čadou.
Tím končím, začínáme se opakovat.
Ale blbost. To je jako byste řekl, že důkazem, že dřevo hoří je pokus, při kterém se prokázalo, že voda nejde zapálit. Si říkejte co chcete, ale jste vedle.
Zaprvé, konstruktor je funkce třídy, jehož jediným úkolem je inicializovat instanci třídy. Lepší by bylo, kdyby se to implementovalo tovární funkcí „createInstance“, na objektu třídy. Jenže z implementačních důvodů tyto jazyky nemají třídy chápány jako objekty, ale spíš jako šablony objektů. Proto konstruktor. Technické řešení vyplývající ze způsobu implementace OOP.
Za druhé, vyplývajícího z funkce konstruktoru je, že konstruktor nemůže a ani není určen k inicializaci jiného objektu, než objektu, který vzniká instanciací třídy. A navíc konstruktor je chápan jako členská funkce instance, ne třídy. Má zvláštní postavení hlavně proto, že je spouštěn na nezkonstruovaný objekt, což může v některých jazycích, ktere objekty mapují přímo do paměti problém, proto se používá konstruktor, aby po vytvoření objektu byl objekt zkonstruován. Prostě když už nic jiného, tak účelem konstruktoru je zvalidovat přidělený paměťový prostor, asi jako bagr, který přijede na rozorané pole, aby tam udělal základy domu.
To vy chcete je tovární funkci, která zkonstruuje jiný objekt. Ale ten objekt se zkonstruuje voláním jeho konstruktoru. Cítíte ten rozdíl? V C++ konkrétně se vytvoření instance skládá ze dvou kroků, neprve přidělení paměti a následně zavoláním konstruktoru na tu paměť. Vůbec netuším, co by mělo znamena, že konstruktor má vytvořit jiný objekt. Asi jako když matka porodí dítě a to se po porodu rozhodne stát psem.
Ukažte mi použití vašeho konstruktoru, abyste mi vyvrátil pocit, že tomu rozumíte jak koza petrželi.
No, je-li tohle pravda (a já nepopírám, že takový výklad dává smysl), je IMO snad lepší OOP nepoužívat, tedy vyjma speciálních domén. Osobně dávám přednost programům, které dělají to, co chce programátor a ne to, co si objekty usmyslí. ;-) Ideální program je snadno verifikovatelný a srozumitelný a to ten OOP přístup v extrémním případě naprosto rozbíjí a představuje neřízenou střelu. Samozřejmě chápu, že OOP přináší určité výhody (zapouzdření, znovupoužitelnost) a užitečné konvence (Demeterův zákon), ale upřímně, nic z těch věcí, které považuju za významné, nevyžaduje posílání zpráv namísto volání metod. Ba co víc, mnohé věci řeší srovnatelně efektivně například funkcionální programování. A po docela obstojných zkušenostech s dynamickými jazyky začínám čím dál tím více uznávat užitečnost kvalitního statického typového systému, který poskytují jazyky z širší rodiny ML (např. Haskell a Scala).
__getattr__
instance = Trida(parametr)
self je zbytečnej opruz, to je fakt. Ale na druhou stranu, kdyby self skryli (něco jako „implicitní“ parametr metody), tak by to nebylo nic víc než syntaktický cukr.
Spíš mě fakt štve ta naprostá absence kontroly. Boo je v tomhle daleko příjemnější – když člověk opravdu chce dynamické chování, použije duck typing a v ostatních případech si užívá pohodlí automatické kontroly. Když se k tomu ještě přidá typová inference, je z toho skoro ideální jazyk ;)
Cyklus nekonečný = nekonečný cyklus.
Vážený pane, když nevíte, co znamená svoboda, tak to fakt nemá cenu. Svoboda znamená, že k výchozího stavu se do libovolného konečného stavu dostanete pomocí několika kroku a libovolnou cestou. Nesvoboda znamená, že do některých konečných stavů se buď vůbec nedostanete, nebo vás to bude stát obrovskové úsilí a budete mít velmi omezený výběr cest.
Považuji jazyky automaticky dělající určité věci za programátora za nesvobodné, protože jejich automatické nástroje nelze deaktivovat. Pokud se budu 10× objektu číslo ptát na faktoriál, tak 10× se bude někde v pozadí vyhodnocovat odesílání zprávy a hledat se program, který bude počítat zadanou úlohu, zatímco rychlejší cesta by byloa vyhodnotit to jednou a pak to vyřešit. Jistěže existují optimalizace, cache a buh ví co, ale to je asi jako když evropská unie látá problémy regulací dalšími regulacemi.
Zkuste ve smalltalku napsat program pro kompresi LZW. Určitě to zvládnete, ale porovnejte výslednou výkonnost s nativním řešení(třeba v C). A to je přesně ta nesvobodam protože vy pak už nemáte jinou možnost, než to napsat v nativu a připojit to jako externí modul, jelikož Vám ten jazyk nedává jinou možnost.
Tím neříkám, že svoboda je lepší. I svoboda má svou cenu. Někdo prostě radši má nástroje k dispozici a vybere si cestu, která mu nejlíp vyhovuje. Jiný si řekne, že to nechá na někom jiném a k cíli se nechá vést za ručičku.
Nezapomeňte že cílem všech jazyků je říct lidsky pochopitelnou formou počítači, co má udělat. U některých jazyků to ale znamená, že jednoduché sdělení bude znamenat obrovskou záťež pro celý stroj. V jiných jazycích budete toho muset hodně namluvit, aby počítač pochopil, co chcete udělat. Já osobně považuji to druhé za svobodnější prostředí, než to první.
Od kdy je nativním jazykem počítačů Cčko?
Já bych tedy byl dost opatrný v používání slova svoboda v souvislosti s programovacími jazyky. Co se týká řešení, tak už tady bylo řečeno, že všechny jazyky, o který se tu nejmenovitě bavíme, jsou turingovsky úplné. Tudíž i množstvím cest se neliší.
Liší se tak akorát efektivitou běhu, což je implementační problém, nikoli problém jazyka a případně efektivitou programování či čitelností kódu.
No Cčko je nativní vícéméně od té doby, co C bylo vymyšleno tak, aby převod do strojáku byl víceméně 1:1 Rozhodně pro překlad a běh nepotřebujete virtuální stroj, ani JIT compiler. Tím je myšleno nativní. A já tim ani nemyslel jazyk, ale výsledný kód, který je ve strojáku „as-is“. Proto se v něm do dnes vyvýjejí operační systémy.
Co mi ovsem na nizkourovnosti Cecka zacina dost citelně chybět, je podpora VLIW obecně, konkrétně MMX, SSE a SSE2. Už to, že v céčku nejde pracovat s flagy (asi kvůli přenositelnosti) některé algoritmy neumožňuje čistě napsat (vícebajtová aritmetika například, tj. sekvence ADD, ADC, ADC, ADC, ADC…) ale nějaká možnost použít výše uvedenu instrukční sadu – to by jazyku jako C slušelo :-)
Nějak mi uniká, co tím vlastně chcete říci. C není žádným suprémem v oblasti lidské pochopitelnosti, ani programátorské svobody, ani rychlosti kódu. Smalltalk je rozhodně lidsky pochopitelnější, jednodušší a čistší jazyk, než C. Pokud jde o programátorskou svobodu, tak tady asi konkurenci nemá Forth – můžete si v něm udělat cokoli, jakkoli, za ručičku Vás tu určitě žádný překladač nevede – ovšem se všemi důsledky, jež z toho plynou. A pokud jde o efektivitu kódu, tak – nepočítám-li Assembler – tady (pro někoho možná kupoodivu) vítězí Fortran. Vím, je nesmysl porovnávat v tomto ohledu jazyky, když je to záležitost překladačů, ale filosofie jazyka má na návrh jeho překladače a možnosti optimalisace poměrně velký vliv. No a že Smalltalk podporuje objektový přístup lépe, než C++, to je prostě fakt – C++ = „objektový assembler“. Já jsem žil ovšem vždycky v přesvědčení, že tak to taky bylo myšleno. Flame by IMHO mohl vzniknout na téma „je lépe objektový Smalltalk nebo Lisp (CLOS)“, kde oba jazyky nabízejí luxusní nástroje pro OOP, ale každý to realizuje úplně jinak. Smalltalk je 1. liga v OOP, CLOS je 1. liga v OOP, ale C++ – to určitě první objektová liga není.
Jinými slovy – že dáváte přednost C++ je sice hezké, ale je to věc, jež má tu zajímavou vlastnost, že z ní o Smalltalku a OOP vůbec nic neplyne. :-)
Myslím, že se tady míchá svoboda (volnost) jazyku s jeho účelem. Smalltalk vznikl jako vyšší jazyk pro řešení rozsáhlých abstraktních úloh, čehož je komprese LZW přesným opakem. Komprimovat nikdy nebylo smyslem Smalltalku. Naopak jde o typickou výpočetně a datově jednoduchou úlohu, pro kterou jsou přímo určeny jazyky assembler a C.
Užití nevhodných jazyků pro řešení specifických úloh není v praxi neobvyklou chybou.
Co kdo povazuje za svobodu a upresneni jejiho vykladu v dane situaci muze byt na miste. Dotazujici se muze ujistovat, zde svoboda neni vice zamenovana napriklad za zbozne prani. Zaroven se ujistete, zda Vase svoboda neni jen Vasim zboznym pranim.
Co se tyka implementace LZW, tak jste to trefil – ano, mame ruzne kese, zname a mame JIT pro runtime preklady a dalsi nastroje a metody, ktere dokazi zdanlive neefektivni jazyk ucinit efektivnim a mnohdy efektivnejsim nez v pripade, ze by to programator psal v cecku nebo strojaku. Pokud mam dnes dobry jazyk, tak zitra muzu mit i dobrou implementaci prekladu toho jazyka pro prislusny stroj. Nadcasovost jazyka nepovazujte za chybu, to by byla chyba.
Pro me znamena svobova (kdyz se bavime o vyvoji):
- moznost vybrat si nastroj, ktery mi pro dany ukol nejlepe vyhovuje (pokazde to muze byt neco jineho – BASH, Python, ciste C, assembler, PL/SQL, C++)
- moznost menit si ten jazyk nebo knihovny pod rukama (zkuste vymenit v C nebo Jave defaultni random() za neco lepsiho – opruz)
- samozrejme neco na zpusob LGPL je jen vyhodou
Oblíbeným omylem všech OOP nováčků je lpění na „posílání zpráv“. Poukazovat na to, že tamten jazyk posílá zprávy a jiný jazyk zprávy neposílá ale volá metody. A že tamten jazyk jen říká co by měl objekt udělat a ten druhý mu přímo nařizuje, co má udělat. Ale to jsou všechno pitomosti.
No já ti nevím, když na tom bazíruje největší OOP nováček ze všech. Nic mě nezlepší náladu víc, než když se od srdce po ránu zasměju, děkuji.
No to je odpoved za vsechny prachy :-)
Ale k veci. Otazka je co myslite zmenou struktury. pridani/odebrani/zmena metody neni problem, metody se drzi kontejneru ve tride daneho onjektu.
Zmena layoutu objektu (pridani/odebrani instancni promenne – fieldu chcete-li)
je zajimavejsi. Na to jsou v zasade dve reseni:
1) vytvori se kopie nove tridy se patricnymi zmenami a ta se nainstaluje do
systemoveho slovniku. Stare objekty (vytvorene pred zmenou) si referencuji
starou tridu…az vsechny stare objektu vymrou, pojde i trida (je treba si
uvedomit ze tridy. metody, bytekod – to vsechno jsou normalni objekty
pod nadvladou GC)
2) Objekty se zmigruji na novou verzi. Data se proste „prekopiruji“ tak. aby
to vyhovovalo novemu layoutu. To je trosku tricky a aby to slo udelat
efektivne (rychle) je potreba pouzivat neprime ukazatele na objekty
(jako VW a GST). Squeak (a St/X ci Dolphin) pouzivaji direct-pointers,
takze tam je tahle operace relativne draha.
Vetsinou se pouziva ta prvni varianta, nebot je to jednodussi na implementaci,
vetsinou to staci a kdyz ma nekdo potrebu, tu druhou variantu si muze vzdycky
naprogramovat (a je to na par radek, alespon ta zakladni verze)
Nekonzistence dat: to je otazka co to znamena. Pokud to znamena ze si date
do objektu bordelni data, pak budiz Vam zeme lehka :-)
No v podstate sa dá ľahko pochopiť, čo to robí pri jednoduchých zmenách – v danom prípade priradil inú farbu asteroidom, engine hry pri nasledujúcej iterácií zbehne danú metódu a proste budú mať asteroidy novú farbu.
Ale keď zmením triedu tak, že zmažem (inštančnú) premennú a niekde sa na ňu odkazujem…to je ten prípad čo popisujete..dovolí mi to vôbec „update“? (dalo by sa to otestovať, ale nemám moc čas teraz študovať smalltak a squeak)
Ďalšia vec – predpokladom je, že vďaka zapúzdreniu sa na tú premennú odkazujem len v mojej triede. (hoci ak mám k dispozícií celý image, asi sa to dá ošetriť aj bez toho)
To 1) riešenie sa mi zdá trochu zbytočné, napr. objekt Application s referenciami na moje objekty asi za behu nevyhynie.
Zaujímam sa o toto, lebo som čítal niekde o EVE Online, ako vďaka stackless pythonu, citujem
„We can make changes to the code and see the effects in the running client or server without restarting them.“.
čo ma dosť zaujalo, ale ani po dlhšom googlení som nezistil, ako je to konkrétne realizované, vyzerá to skôr na nejaké in-house riešenie.
Smalltalk s takovými zásahy počítá. Pokud odstraní používaná instanční proměnná, překompiluje se změněná třída a její podtřídy. Pokud se neexistující instanční proměnná někde používána, dá se na její místo asociace na nil, která se uloží do globální kolekce Undeclared. Takže například všechny accessory na danou instanční proměnnou ve všech objektech dané třídy začnou vracet nil (bez vyhození výjimky). Z jiných tříd se na instanční proměnné jako takové odkazovat nejde. Pokud se použila někdy před tím, muselo to být pomocí zavolání zprávy a pak se referencuje konkrétní objekt, kterého se změna ve třídě jednoho objektu, který ji referencoval nebo referencuje, nijak netýká.
Jestliže se smaže třída (např. Person), která má instanční proměnné, je někde používána nebo má podtřídy, je nahrazena tzv. obsolete třídou (AnObsoletePerson) a přidá se do kolekce obsoleteClasses. Díky těmto kolekcím (Undeclared, obsoleteClasses) se podobné nekonzistence v systému hledají a odstraňují poměrně snadno.
Smalltalk relativně bez úhony přežije i poměrně brutální zásahy. Pokud si ale pod sebou uřežete větev obzvláště bezohledně, většinou o provedené změny nepříjdete, protože se postupně logují do souboru changes a dají se snadno zrekonstruovat.
Ten příklad v Javě uvedený v článku mě zaujal, ještě včera (skoro předevčírem) jsem netušil, že se takto jedna instance třídy může hrabat v atributech instance jiné. Není to porušení zapouzdření a proč to vlastně je takto navržené (možná nějaká optimalizace pro jednodušší kompilaci?)
Práva přístupu v OOP nemá až takový význam. Lze je dodržovat i bez nutnosti mít na to jazyk připravený. Je jedno, jestli Vám tu blokaci udělá překladač, poznámka u proměnné, nebo Váš mozek (v duchu předchozích postů, to je o té OOP filozofii).
Nevím, jak se chová Java, ale v C++ se lze hrabat v atributech objektů téže třídy přímo. Vysvětlení je takové, že metody, které třída implementuje nejsou vlastnictvím instancí, ale zůstávají vlastnictvím třídy. Instance je pouze „dědí“. A protože metody vědí, jaký význam má každá instance toho atributu v každé instanci třídy, mohou tyto atributy měnit. V ideálním OOP tohle nejde, protože objekt po svém vzniku se může vyznamně změnit, může například ten atribut odstranit, nebo změnit jeho význam (tedy nejde jen o změnu hodnot, ale i struktury). Protože, ony vlastně v ideálním OOP třídy neexistují, všechno jsou to jen objekty.
Tohle ale není zábrana, proč by se v Javě, nebo v C++ nemělo dát OOP programovat. Jsou to jen určitě OOP modely, které mají některé speciality.
Největší hodnota zapouzdření je v tom, že garantuje hranici objektu, za kterou je vše v bezpečí. V okamžiku, kdy zmizí zapouzdření, stav vnitřku není možno zaručit. Spoléhat na disciplínu uživatelů objektu je nesmysl. Je to jako spoléhat na řidiče, že budou dodržovat rychlost (=hranici).
Z toho je taky vidět, jak to myslí Java a C++ s objekty vážně, když je možno vlastnosti objektu udělat public. V Ckanál je to syntakticky komplikovaně opraseno pomocí get a set…
Neuvažujete dvě věci:
1) Programovací jazyky nemají o uživatele vychovávat. To je ta pomyslná svoboda vs vedení za ručičku, jak se tu někdo ptal, co se tím myslí.
2) V Javě i v C++ to MÁ opodstatnění, protože každý objekt má vlastně jen atributy, ale instance sdílí metody. Proto nemůže přístup do atributů jednoho objektu z metod jiného objektu způsobit nepředvídatelné potíže. Pokud by někdo do systému „vrhnul“ objekt jiného „typu“, pak už tam přístup mít nebude. Jedná se o modifikátory private ale i protected, pokud jde o zásah do atributů předka potomkem, v případě, že jde o jinou instanci. Prostě vyžadovat „superprivate“ atributy tady jaksi postrádá smysl. OOP v Javě a v C++ je stále stavěno na systémem, že objekty jsou spíš data a kód vykonává JEDNA třída. A je blbost, aby si ta JEDNA třída dělala getry a setry. Asi jako kdyby v jiných OOP jazycích, kde to mají blíže ideálu si k atributům objekt přistupoval přes svoje getry a setry.
Mimochodem co říkáte na property? I to patří do OOP, kdy atribut se tváří jako proměnná, ale ve skutečnosti je to properta, která si sama zavolá getr a setr. Co jsem kdysi dávno četl na www.objects.cz, tak to ničemu nevadí. Potom i atributy nemusí nutně být vždy privatní, protože pokud se ten objekt má někdy v budoucnu změnit, udělá se z něho properta a rozdíl se nepozná.
K 1) A o výchovu uživatele jazykem se zde jedná, když mu v něčem jazyk brání (nedostupnost vnitřku objektu), nebo když spoléhá na jeho sebekázeň (nepoužívání přímého přístupu k vlastnostem)???
S výchovou nebo uživatelem to nemá co dělat, účelem je pouze zajištění nedotknutelnosti. Zapouzdření nevzniklo, aby vychovávalo, ale aby garantovalo. Jeho nepřítomnost pro mě neznamená nesvobodu, ale nejistotu. Svoboda (lépe volnost) pro mě ve Smalltalku znamenají např. reflexe, dynamické typování (možno pro Vás přeložit jako nepřítomnost vedení za ručičku typovou kontrolou) a lambda-výrazy, což dává dohromady obrovské možnosti s minimální námahou.
K 2) Tomuto odstavci popravdě vůbec nerozumím.
K termínům: Dochází tu k spojování termínů objekt a instance. Buďto jen objekt (třeba u prototypování) nebo třída+instance (u třídně-instančního modelu). Pod OOP se dnes myslí jazyky hybridní (kombinují imperativní paradigma), čistě objektové se označují jako object languages, pure object languages nebo object based languages.
Property (tak, jak jsem to viděl v Ckanálu) považuju za další zbytečný syntaktický balast.
To se tezko diskutuje, kdyz se hadame nad obecne známými terminy
Třída není podmínka OOP, ale třídně-instanční model je způsob implementace objektového prostředí. Píšu to proto, že když se mluví o tomto modelu, tak termín objekt neříká, zda máte na mysli třídu nebo instanci.
Jediný jazyk, o kterém vím, že implementuje třídy jako instance metatříd (nejsou to ty Vaše šablony???), je Smalltalk. U C++ jsem předpokládal pouze deklarativní model tříd bez toho, aby existovala jako instance, ale péro do ohně za to nedám.
Rozhraní objektu se nazývá protokol a v původním pojetí OOP určitě neslouží k typové kontrole.
Generiku jsem nepochopil, připadá mi jako způsob, jak obejít typovou kontrolu, když už tam je, ale k tomu by mohli něco říct jiní.
Instance – obdobně jako třída – způsob implementace OOP.
Vizte výše: Pokud vím, třídy nejsou v jazycích (až na pár výjimek) implementovány pomocí objektů, ale jsou pouze deklarativní.
„Programátor pracující se šablonami kolikrát právě třídy považuje za instance, a šablony přebírají původní význam tříd.“ V metatřídním modelu (Smalltalk) jsou samozřejmě třídy instance metatříd, ale to programátora nemusí zajímat. Platí to ale u C++? Je možno třídě poslat zprávu class, která vrací třídu dané třídy? A další zprávy?
Privátní musejí být proto, že dle původní myšlenky OOP do vnitřku objektu nikomu nic není a když něco chce, tak se zeptá. Gettery a settery jsou v podstatě to samé, jako přístupové metody, proti kterým samozřejmě nic nemám, ale proč na to vyrábět další syntaktickou konstrukci, kterých je v Ckanálu už tak mraky, to nechápu.
Ještě jednou k property: Samotné vystavení vlastností je samozřejmě ztráta zapouzdření, ale jako property se o vystavení nejedná, jsou to jen jinak pojmenované přístupové metody. Ale znovu: Je třeba kvůli tomu rozšiřovat syntax??? Síla Smalltalku je (nejen) v jednoduchosti syntaxe. Už nevím, kde jsem to četl: „Jazyk je dokonalý ne tehdy, když už do něj není co přidat, ale když už není co ubrat.“