🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.os.linux.programowanie
Article #60146

Re: Pogaduchy o językach (było coś o dużej silni)

#60146
From: Marcin 'Qrczak' Kowalczyk
Date: Sat, 05 Nov 2005 22:02
179 lines
9704 bytes
Maciej Sobczak <no.spam@no.spam.com> writes:

>> Nazwy, przez które odwołujemy się do tych obiektów, są lokalne,
>> bo nie są globalne. Same obiekty nie potrzebują cechy lokalności
>> na poziomie języka.
>
> Owszem, potrzebują, bo lokalność pozwala określić też czas życia
> obiektu.

Gdyby tylko pozwalała, to byłby mały problem, ale w C++ ona do tego
zmusza. Przez to nawet gdybyśmy trzymali obiekt za wskaźnik, to
lokalna funkcja nie mogłaby odwoływać się do tej samej zmiennej
wskaźnikowej po zakończeniu zewnętrznej funkcji, bo destrukcja
wskaźnika, choć w praktyce nic nie robi, powoduje, że zmiennej
nie wolno już używać.

> Często korzystam z obiektów tymczasowych, które nazwy nie mają a
> mimo to polegam (!) na gwarancjach, które daje mi język w temacie
> czasu ich życia. Bez takich gwarancji pewnych rzeczy w ogóle nie
> mógłbym wyrazić tak, jak chcę.

Ja takich obiektów używam nieporównywalnie rzadziej niż lokalnych
funkcji; w ogóle nie przypominam sobie przypadków, kiedy obiekt
o destruktorze zwalniającym coś więcej niż pamięć miałby nie mieć
nazwy. Więc nie przeszkadza mi cięższa składnia przy deterministycznym
zamykaniu obiektów.

>> Wystarczy tylko przez referencję. Dostęp przez wartość jest
>> szczególnym przypadkiem dostępu przez referencję, bo to po prostu
>> dostęp do innego obiektu, do kopii tego pierwszego.
>
> OK. Wymaga to jednak dodatkowej składni (trzeba coś zrobić, żeby
> stworzyć kopię).

To jest sprawa niezależna od lokalnych funkcji. Nie wymaga to *nowej*
dodatkowej składni, tylko użycia tego, czego teraz już się używa dla
zrobienia kopii.

> void foo()
> {
>      int local_object;
>
>      bind(
>          void (int i) { cout << i; },  // lambda z jednym parametrem
>          local_object                  // dowiązanie local_object do i
>      )();                              // aplikacja obiektu funkcyjnego
> }

To się nie skaluje do większych przykładów. Listowanie zmiennych
wolnych każdej lokalnej funkcji będzie przykre.

Przykład. Oryginalna funkcja z mojego kompilatora (tłumacząca
wyrażenie między jedną a drugą postacią pośrednią, kiedy wyrażenie
jest używane w kontekście wartości logicznej, a samo jest postaci
'case' - mniejsza z tym, jak działa):

let PlanIf (exprL ! LE_CASE) loc trueCont falseCont {
   let (planSubjs, planParams, lastCase) = CaseMatcher exprL;
   planSubjs exprL.subjs ?subjsQ =>
   MultiCont trueCont ?trueCont =>
   MultiCont falseCont ?falseCont =>
   loop exprL.cases [
      (caseL\caseLs) {
         planParams caseL.params subjsQ False
         (PlanIf caseL.then loc trueCont falseCont) Then%
         if (lastCase caseL.params) {QSEmpty}
         else {again caseLs}
      }
      [] {QSFail exprL.loc (QEName DoesNotMatchN)}
   ]
};

Składnia '?parametr => ciało' to lambda. Spróbowałem przetłumaczyć to
na C++. Najpierw uwagi, potem kod:

loop rozwija się do lokalnej rekurencyjnej funkcji, która od razu jest
aplikowana do początkowych argumentów. Nie robię z tego pętli C++, bo
rekurencja nie jest tutaj ogonowa.

Założyłem, że wynik bind tworzącego jednoargumentową funkcję zapisuje
się tak: fun<Arg,Wynik>.

Założyłem, że mamy też rec_bind, które jako ostatni argument
przekazuje ciału funkcji samą stworzoną właśnie funkcję.

Dla uproszczenia wskaźniki na moje typy to gołe wskaźniki, bo
nie wiem, jaki rodzaj sprytnych wskaźników byłby tutaj odpowiedni.
Założyłem, że mamy szablon list z wymyślonym na poczekaniu
interfejsem; on nie ma tutaj znaczenia.

Pojawił się w dwóch miejscach const void *, bo w oryginalnym programie
typ jest różny w zależności od decyzji podjętej przez CaseMatcher, ale
zawsze w obu miejscach zgodny. To jest swoją drogą ciekawy przykład,
kiedy statyczne typy przeszkadzają.

typedef QStat *(*PlanExprsOrListExpr)(list<const LExpr *>,
                                      fun<const void *, const QStat *>);
typedef QStat *(*PlanPatsOrListPat)(list<const LPat *>,
                                    const void *,
                                    bool,
                                    const QStat *);
typedef bool (*LPatsPred)(list<const LPat *>);

QStat *LECase::plan_if(Location loc,
                       const QStat *true_cont,
                       const QStat *false_cont) const {
   PlanExprsOrListExpr plan_subjs;
   PlanPatsOrListPat plan_params;
   LPatsPred last_case;
   boost::tie(plan_subjs, plan_params, last_case) = case_matcher();
   return plan_subjs(subjs, bind(
      QStat *(const void *subjs,
              const QStat *true_cont,
              const QStat *false_cont,
              const LECase *expr,
              PlanPatsOrListPat plan_params,
              Location loc,
              LPatsPred last_case) {
         return multi_cont(true_cont, bind(
            QStat *(const QStat *true_cont,
                    const QStat *false_cont,
                    const LECase *expr,
                    PlanPatsOrListPat plan_params,
                    const void *subjs,
                    Location loc,
                    LPatsPred last_case) {
               return multi_cont(false_cont, bind(
                  QStat *(const QStat *false_cont,
                          const LECase *expr,
                          PlanPatsOrListPat plan_params,
                          const void *subjs,
                          Location loc,
                          const QStat *true_cont,
                          LPatsPred last_case) {
                     fun<list<LCase *>, QStat *> loop = rec_bind(
                        QStat *(list<LCase *> cases,
                                const LECase *expr,
                                PlanPatsOrListPat plan_params,
                                const void *subjs,
                                Location loc,
                                const QStat *true_cont,
                                const QStat *false_cont,
                                LPatsPred last_case,
                                fun<list<LCase *>, QStat *> again) {
                           return cases.is_empty() ?
                              new QSFail(expr->loc,
                                         new QEName(DoesNotMatchN)) :
                              then(plan_params(cases.first()->params,
                                               subjs,
                                               false,
                                               cases.first()->plan_if(
                                                  loc, true_cont, false_cont)),
                                  last_case(cases.first()->params) ?
                                     new QSEmpty :
                                     again(cases.rest()));
                        }, expr, plan_params, subjs, loc, true_cont,
                        false_cont, last_case);
                     return loop(expr->cases);
                  }, expr, plan_params, subjs, loc, true_cont, last_case));
            }, false_cont, expr, plan_params, subjs, loc, last_case));
      }, true_cont, false_cont, this, plan_params, loc, last_case));
}

Fajne, nie?

> Oczywiście, local_object ma *skończyć życie* przy wyjściu z foo().
> Nie ma prawa żyć dłużej, niż trwa wykonywanie foo().

Wolę mieć tutaj wybór.

> Powiem po raz (n+1)-szy: Twój model nie jest uniwersalny i nie trafia
> w oczekiwania *wszystkich* programistów.

Ależ temu nie zaprzeczam. A do mnie nie trafia model C++.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
Technical Details
Message-ID: <87mzkihhww.fsf@qrnik.zagroda>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news2.icm.edu.pl!wsisiz.edu.pl!newsfeed.tpinternet.pl!atlantis.news.tpi.pl!news.tpi.pl!not-for-mail
References: <djfrn5$i55$1@nemesis.news.tpi.pl> <87wtk0iiqw.fsf@qrnik.zagroda> <djq3rj$4fm$1@sunnews.cern.ch> <87y84fz1bn.fsf@qrnik.zagroda> <djqg9q$1sg$1@sunnews.cern.ch> <87ll0ezpyl.fsf@qrnik.zagroda> <djsle0$q36$1@sunnews.cern.ch> <877jbx7q2t.fsf@qrnik.zagroda> <dk4n41$aue$1@sunnews.cern.ch> <87vezdanl0.fsf@qrnik.zagroda> <dk9su1$6su$1@sunnews.cern.ch> <87k6fqeq35.fsf@qrnik.zagroda> <dkcps0$2vq$1@sunnews.cern.ch> <slrndmk3v4.p01.jajcus@serwis2.beta> <dkd731$2u6$1@sunnews.cern.ch> <87psphsc6n.fsf@qrnik.zagroda> <dkf5da$d8g$1@sunnews.cern.ch> <87mzkk8xc0.fsf@qrnik.zagroda> <dkfmp9$msh$1@sunnews.cern.ch> <87ek5wt6iw.fsf@qrnik.zagroda> <dkj057$2bj$1@sunnews.cern.ch>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news2.icm.edu.pl!wsisiz.edu.pl!newsfeed.tpinternet.pl!atlantis.news.tpi.pl!news.tpi.pl!not-for-mail
From: Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl>
Newsgroups: pl.comp.os.linux.programowanie
Subject: Re: Pogaduchy o językach (było coś o
 dużej silni)
Date: Sat, 05 Nov 2005 23:02:55 +0100
Organization: Klub Nieszkodliwych Manjaków
Lines: 179
Message-ID: <87mzkihhww.fsf@qrnik.zagroda>
References: <djfrn5$i55$1@nemesis.news.tpi.pl> <87wtk0iiqw.fsf@qrnik.zagroda> <djq3rj$4fm$1@sunnews.cern.ch> <87y84fz1bn.fsf@qrnik.zagroda> <djqg9q$1sg$1@sunnews.cern.ch> <87ll0ezpyl.fsf@qrnik.zagroda> <djsle0$q36$1@sunnews.cern.ch> <877jbx7q2t.fsf@qrnik.zagroda> <dk4n41$aue$1@sunnews.cern.ch> <87vezdanl0.fsf@qrnik.zagroda> <dk9su1$6su$1@sunnews.cern.ch> <87k6fqeq35.fsf@qrnik.zagroda> <dkcps0$2vq$1@sunnews.cern.ch> <slrndmk3v4.p01.jajcus@serwis2.beta> <dkd731$2u6$1@sunnews.cern.ch> <87psphsc6n.fsf@qrnik.zagroda> <dkf5da$d8g$1@sunnews.cern.ch> <87mzkk8xc0.fsf@qrnik.zagroda> <dkfmp9$msh$1@sunnews.cern.ch> <87ek5wt6iw.fsf@qrnik.zagroda> <dkj057$2bj$1@sunnews.cern.ch>
NNTP-Posting-Host: paf87.warszawa.sdi.tpnet.pl
Mime-Version: 1.0
X-Trace: nemesis.news.tpi.pl 1131228223 3069 217.96.225.87 (5 Nov 2005 22:03:43 GMT)
X-Complaints-To: usenet@tpi.pl
NNTP-Posting-Date: Sat, 5 Nov 2005 22:03:43 +0000 (UTC)
X-Face: .B/ouEO}=VFkSJWE}s0@!:diHI.Z,<Ilt`:~@*]7rnn^K_y"XV8AXf^E)x*|3yVg:$FCq0Y )iGn@Z[SOA<+p}TkAv'Lzu$w{z2?F);0Xt>`m}AqK#Vjuscq(Vf1B}H[)v\9tBN}>AdP,QSRbhO]=v 3?;I+cN/Z0HKPm_Eg99/pFrU!WfpjgQ!z":>A~qt0^4):0-UuPB(6^>j!mN$)RIb)rRhXeK:+MLPW[ RVb7Kepvby-ww6_zci7Yy_@IrWW
User-Agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)
Cancel-Lock: sha1:EvrE4LYi9X9SydKP9f22XTgC478=
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit