hilpers


  hilpers > comp.lang.* > comp.lang.c

 #1  
27.06.2008, 07:54
Seweryn Habdank-Wojewódzki
Witam

Wszystkim fanom dynamicznego typowania polecam przeczytac krotkie
opracowanie [1].
Dosc ciekawa jest dyskusja ponizej, a szczegolnie tematy zwiazane z
Poco::DynamicAny [2].

Dla nabrania smaku podaje:

# Python
any = '42'
i = int(x)
any = 65535
s = str(x)

Podobny kod w C++

DynamicAny any("42");
int i = any; // i == 42
any = 65536;
std::string s = any; // s == "65536"

// mozna tez dodac jeszcze takie cos:
char c = any; // too big, throws RangeException

Tego powyzej nie umiem napisac w Pythonie jak ktos potrafi to prosze o
uzupelnienie.

Pozdrawiam,

[1] http://herbsutter.wordpress.com/2008...ynamic-typing/
[2] http://pocoproject.org/poco/docs/Poco.DynamicAny.html
 #2  
27.06.2008, 08:24
Seweryn Habdank-Wojewódzki
> // mozna tez dodac jeszcze takie cos:
> char c = any; // too big, throws RangeException


# Python
c = chr(any) // rowniez sypnie wyjatkiem
 #3  
27.06.2008, 09:01
Artur M. Piwko
In the darkest hour on Fri, 27 Jun 2008 00:24:42 -0700 (PDT),
Seweryn Habdank-Wojewódzki <habdank> screamed:
[..]
 #4  
27.06.2008, 09:17
Krzysiek Kowaliczek
Seweryn Habdank-Wojewódzki wrote:
> Wszystkim fanom dynamicznego typowania polecam przeczytac krotkie
> opracowanie [1].


Dynamiczne typy w C++ nie byly mi do tej pory potrzebne.
Natomiast chetnie zobaczylbym bym coś na ksztalt typów
wariantowych, znanych z jezyków funkcjonalnych. Zwlaszcza,
ze stanowilyby doskonaly zamiennik dla znienawidzonego,
przez mnie, wzorca wizytor. Ponizej przyklad:

case class Expression
{
cases
{
class BinaryExpression;
class UnaryExpression;
class NumberExpression;
};
};

class BinaryExpression:
public Expression
{};

class UnaryExpression:
public Expression
{};

class NumberExpression:
public Expression
{};

void foo ()
{
const Expression& e = getExpression ();
switch ( e )
{
case BinaryExpression x:
break;
case UnaryExpression x:
break;
case NumberExpression x:
break;
};
}

Co myślicie o przydatności takiej konstrukcji? Moze ktoś wie
czy tego typu pomysly byly rozwazane w przyszlej wersji
standardu?

Pozdrawiam
KK
 #5  
27.06.2008, 13:30
Wiktor Zychla
> ze stanowilyby doskonaly zamiennik dla znienawidzonego, przez mnie, wzorca
> wizytor. Ponizej przyklad:


osobiście uzywam metody wirtualnej w klasie bazowej, zwracającej TYP
wyrazenia, przeciązonej w klasach wariantowych zeby robic switch po typie.

C#:

enum ExpressionType { None, Unary, ... };

class Expression
{
virtual ExpressionType Type;

// do rzutowania na typy wariantowe, przydatne w switch ponizej
T OfType<T>() { return (T)this; };
}

class UnaryExpression
{
override int Type = ...;
}

void Foo()
{
Expression e;
switch ( e.Type )
{
case ExpressionType.Unary :
e.OfType<UnaryExpression>()
}
}

// przez mnie, wzorca wizytor. Ponizej przyklad:

prosze o wyjaśnienie co ma do tego wzorzec wizytor.

Wiktor Zychla
 #6  
27.06.2008, 13:49
Wiktor Zychla
> DynamicAny any("42");
> int i = any; // i == 42
> any = 65536;
> std::string s = any; // s == "65536"


fajne, ale mam pewne pytanie:

nie wiem jak to jest zaimplementowane, ale spekuluje, ze "typ" any bedzie
zawsze DynamicAny, natomiast w dynamicznym typowaniu chcialoby sie zeby
"typ" wyrazenia zmienial sie w zaleznosci od kontekstu i zeby to runtime
engine decydowal o tym co robic dalej z efektami zmian typów (a nie
kompilator).

a wiec:
- jesli to "dynamiczne typowanie" polega na poprzeciazaniu operatorów
przypisania, to w istocie nie ma tu zbyt wiele dynamizmu, bo dla kazdego
operatora przypisania kompilator i tak STATYCZNIE widzi typy elementów po
jednej i po drugiej stronie wyrazenia i uzyje odpowiedniej wersji
przeciazonego operatora.

- natomiast dynamiczne to to typowanie byloby, gdyby typy wyrazen
wystepujacych w wyrazeniu przypisania nie byly znane i kompilator w któryms
miejscu nie wiedzialby jaki prawdziwy typ ma dane wyrazenie, natomiast ten
typ znany bylby w runtime.

cos w stylu:

class Bar { }

DynamicAny Foo1()
{
if ( warunek )
return 1;
else
return new Bar();
}

DynamicAny Foo2()
{
if ( warunek )
return 1;
else
return new Bar();
}

void Baz()
{
Foo1() + Foo2();
// tu kompilator co prawda wie, ze operator sumowania aplikuje sie do
// dwóch obiektów typu DynamicAny, ale
// w jezykach z dynamicznym typowaniem to zadziala zawsze
// - gdy oba Foo() zwróca jedynke (bo dodadza sie do siebie dwie jedynki)
// - gdy oba Foo() zwróca Bar() zostanie wywolany operator + na Bar
// (+ zostanie rozwiklany w runtime)
// w jezyku z dynamicznym typowaniem "udawanym" przez operatory konwersji
// to nie przejdzie, bo operator + na DynamicAny na pewno nie potrafi
obsluzyc
// przypadku gdy dodawane sa obiekty nieznanego mu w czasie kompilacji
typu
// Bar
}

Wiktor Zychla
 #7  
27.06.2008, 14:09
Krzysiek Kowaliczek
Wiktor Zychla wrote:
> osobiście uzywam metody wirtualnej w klasie bazowej, zwracającej TYP
> wyrazenia, przeciązonej w klasach wariantowych zeby robic switch po typie.
>
> C#:
>
> enum ExpressionType { None, Unary, ... };
>

[ciach]
> Expression e;
> switch ( e.Type )
> {
> case ExpressionType.Unary :
> e.OfType<UnaryExpression>()
> }
> }
>


Nie znam C#. Czy wygeneruje on ostrzezenie, jezeli do
ExpressionType dodamy nastepny element, a nie uzupelnimy
odpowiednich konstrukcji switch? Jezeli tak, to jest to
jakieś rozwiązania. W C++ takich mozliwości niestety nie ma.
Osobiście w takich przypadkach, w C++, stosuje statyczną
asercje:
enum ExpressionType { None, Unary, ..., Num };
BOOST_STATIC_ASSERT ( Expression::Num == 10 )
switch ( e.type ())
{
/// ...

Przynajmniej bede wiedzial gdzie mam zmodyfikowac kod.
Niestety wymaga do samodyscypliny i jest uciązliwe.

>
> prosze o wyjaśnienie co ma do tego wzorzec wizytor.
>


Szerzej tutaj:
http://www.inspirel.com/articles/Visitor_Revisited.html

Pozdrawiam
KK
 #8  
27.06.2008, 14:31
Wiktor Zychla
> http://www.inspirel.com/articles/Visitor_Revisited.html

ok, juz widze jak chcialeś do tego uzywac visitora.

przyklad jest o tyle wymowny, ze zaproponowana alternatywa to dokladnie coś
takiego o czym rozmawiamy.

> Nie znam C#. Czy wygeneruje on ostrzezenie, jezeli do


niestety :( ja najcześciej stosuje klauzule default, która wyrzuca wyjątek,
a o tym, ze czegoś zapomnialem dopisac dowiaduje sie w trakcie testów.

Wiktor Zychla
 #9  
27.06.2008, 14:41
Paweł Kierski
Krzysiek Kowaliczek w wiadomości <g427fb$1fl$1> pisze:
[..]
> case UnaryExpression x:
> break;
> case NumberExpression x:
> break;
> };
> }
>
> Co myślicie o przydatności takiej konstrukcji? Może ktoś wie
> czy tego typu pomysły były rozważane w przyszłej wersji
> standardu?


Dla mnie tego typu konstrukcja (switch po typie) zawsze "brzydko
pachnie". Czy tego, co miałoby się wykonywać dla poszczególnych
przypadków nie lepiej zawrzeć jako metodę wirtualną wspólnego typu
(interfejsu) bazowego? W tym wypadku: "zrób ogólne foo()":

class Expression
{
public:
virtual void foo() = 0;
};

class BinaryExpression:
public Expression
{
void foo() {foo_as_BinaryExpression();}
};

class UnaryExpression:
public Expression
{
void foo() {foo_as_UnaryExpression();}
};

class NumberExpression:
public Expression
{
void foo() {foo_as_NumberExpression();}
};

i wtedy:

void foo()
{
Expression& e = getExpression ();
e.foo();
}

czyli w praktyce:

getExpression().foo();


Ale może przykład jest zbyt słaby, żeby pokazać, że switch jest
niezbędny/prostszy.
 #10  
27.06.2008, 15:02
Wiktor Zychla
> Ale może przykład jest zbyt słaby, żeby pokazać, że switch jest
> niezbędny/prostszy.


wystarczy pomyśleć o tym, co by było, gdyby każda klauzula switch korzystała
z pewnego podzbioru zmiennych widzianych przez switch, np.

void bar()
{
// tu mam w polu widzenia x, y, z, t, u, v, itd. RÓZNYCH typów

switch ( e.Type )
{
case Type.UnaryExpression:
zrób coś z x, y i z;
case Type.BinaryExpression:
zrób coś z u, v;
}
}

gdyby chcieć mieć jedną wirtualną metodę na Expression, to musiałaby ona
mieć bliżej nie sprecyzowaną sygnaturę. może możnaby użyć do tego przypadku
z powodzeniem refaktoryzacji Introduce Parameter Object, ale w ogólnym
przypadku trudno powiedzieć, który wariant jest lepszy.

Wiktor Zychla
 #11  
27.06.2008, 15:11
Krzysiek Kowaliczek
Paweł Kierski wrote:
> Dla mnie tego typu konstrukcja (switch po typie) zawsze "brzydko
> pachnie". Czy tego, co miałoby się wykonywać dla poszczególnych
> przypadków nie lepiej zawrzeć jako metodę wirtualną wspólnego typu
> (interfejsu) bazowego? W tym wypadku: "zrób ogólne foo()":
>


Odpowiedź jest prosta. Po prostu się nie da. Trudno mi sobie
nawet takie coś wyobrazić. Każde nowe "zrób ogólne foo()"
wymagałoby zmiany we wszystkich klasach pochodnych. To to
już całkowicie łamie zasadę open-close. Biorąc pod uwagę, że
ilość klas jest mniejsza od ilości algorytmów operujących
na nich ( z mojego punktu widzenia ), to już lepszy byłby
wzorzec wizytor.

Pozdrawiam
KK
 #12  
27.06.2008, 15:52
Paweł Kierski
Wiktor Zychla w wiadomości <g42sap$6mk$1> pisze:
[..]
> zrób coś z x, y i z;
> case Type.BinaryExpression:
> zrób coś z u, v;
> }
> }
>
> gdyby chcieć mieć jedną wirtualną metodę na Expression, to musiałaby ona
> mieć bliżej nie sprecyzowaną sygnaturę. może możnaby użyć do tego przypadku
> z powodzeniem refaktoryzacji Introduce Parameter Object, ale w ogólnym
> przypadku trudno powiedzieć, który wariant jest lepszy.


Zgadzam się - w ogólności nie da się powiedzieć, co najlepsze.

Przyznam się, że chodziło mi o podkreślenie, że switch po typie dla
bardziej "regularnych" przypadków (operacje na podobnych listach
argumentów) nie jest najszczęśliwszym rozwiązaniem 8-)
 #13  
27.06.2008, 16:19
Marcin ‘Qrczak’ Kowalczyk
On 27 Cze, 08:54, Seweryn Habdank-Wojewódzki <habd>
wrote:

> [2][..]


Następujący fragment jest moim zdaniem głupi (trudno sobie wyobrazić
sytuację, w której właśnie takie zachowanie byłoby potrzebne):

A string value "false" (not case sensitive) or "0" can be converted to
a boolean value false, any other string not being false by the above
criteria evaluates to true (e.g: "hi" -> true).
 #14  
27.06.2008, 18:47
Seweryn Habdank-Wojewódzki
Witam

> > c = chr(any) // rowniez sypnie wyjatkiem
> >>> c = unichr(any)
> >>> c

>
> u'\uffff'


Tak. Ale to, ze tamto powyzej sypie wyjatkiem jest bardzo dobre.
Python ma sypnac bledem, bo glupio robie.

Pozdrawiam,
Seweryn Habdank-Wojewodzki.
 #15  
27.06.2008, 18:55
Seweryn Habdank-Wojewódzki
Witam

> A string value "false" (not case sensitive) or "0" can be converted to
> a boolean value false, any other string not being false by the above
> criteria evaluates to true (e.g: "hi" -> true).


Słusznie!

To powinno albo działać w drugą stronę czyli 'true' tylko dla true.
Reszta to false.

Albo w ogóle silno czyli 'true' to true 'false' to false, a reszta
to wyjatek bad_cast.

Pozdrawiam,
Seweryn Habdank-Wojewódzki.

Podobne wątki
Ciekawostka przyrodnicza

Dziś zostałam uraczona chłodnikiem "litewskim" z... krewetkami, w zastępstwie raków, chyba. Hmmm... :/

Ciekawostka przyrodnicza

Regulamin Promocji "Rachunek dyskretny" # Usługa pozwala Abonentowi na rozszerzenie zakresu zachowania w poufności informacji o połączeniach wykonywanych z numeru...

ciekawostka przyrodnicza

> NH4(+) = NH3(+) + H ze niby wodor atomowy powstaje?? dziwne...

ciekawostka przyrodnicza

Jestem dumnym posiadaczem dosyć wiekowego ale do tej pory spisującego się bez zarzutów kompa. Mój zestaw to Plyta główna Acorp 6bx67 z chipsetem 440BX Procesor Celeron 333,...

Ciekawostka przyrodnicza

Co wam to przypomina? (reklama z Gadu-gadu - 17 KB) [..]


Czasy w strefie GMT. Teraz jest 14:57. | Privacy Policy