Przeskakując między wieloma językami programowania, bibliotekami czy frameworkami po pewnym czasie można wyrobić sobie zdolności “uogólniające”, dzięki którym takie zmiany nie są specjalnie kłopotliwe. Jednak nawet jeśli potrafimy płynnie przechodzić od jednego języka do drugiego, to zawsze istnieje szansa, że zapomnimy przy okazji o jakimś szczególe, drobnej rzeczy specyficznej dla konkretnego narzędzia – tytułowym małym kruczku.
A przynajmniej mi się tak nierzadko zdarza. Dlatego tę notkę dedykuję pojedynczym, drobnym a “dziwnym” cechom poszczególnych języków programowania, o których często zdarza mi się zapominać. A są one następujące:
"ala" + " ma " + "kota"
jest najzupełniej oczywistą konkatenacją trzech napisów. Ale w C++ nie. Ponieważ stałe dosłowne, takie jak teksty w cudzysłowach, są – w przybliżeniu – typu const char*
, ich łączenie operatorem +
jest interpretowane jako dodawanie dwóch wskaźników. Serio."ala" " ma " "kota"
, o ile oczywiście nie łączymy obiektów klasy string
.java.lang.String
nie robi wyjątku i obsługuje go tak, jak każdą inną klasę. A to oznacza, że zwykły operator ==
działa dla napisów tak samo, jak dla innych obiektów (inaczej niż choćby w C#), tj. porównuje ich referencje w celu sprawdzenia, czy mamy do czynienia z tym samym obiektem. Tym samym, nie zaś takim samym, czyli równym co do wartości – a o to nam zwykle chodzi, gdy pracujemy z napisami.equals
. To pewnie dlatego wciąż nie ma w niej switch
a dla napisów ;-)który na pierwszy rzut oka wygląda na zupełnie poprawną iterację po zawartości słownika dictionary
, w której zmienna k
dostaje klucz, a v
wartość. Jest on dowodem, że oczami należy rzucać zawsze przynajmniej dwa razy. W istocie bowiem k
i v
będą kolejno otrzymywały, uwaga, po dwa elementy klucza (potraktowanego jako para). Po prostu konwersja słownik → coś_po_czym_można_iterować daje w Pythonie kolekcję kluczy, a nie par klucz-wartość. Nie pytajcie, dlaczego.
Wniosek: Albo iterujemy po kluczach i wartość uzyskujemy zwykłym indeksowaniem, albo korzystamy z metody items
w celu uzyskania kolekcji par klucz-wartość.
var
.Podobny kruczek występuje przy korzystaniu z polimorfizmu (konkretniej metod wirtualnych). C++, C#, Delphi wymagają jawnego podania modyfikatora virtual, natomiast Java traktuje wszystko jako metody wirtualne (co imho w C# też powinno być domyślnym zachowaniem, ale co ja tam wiem :) )
Ja często łapię się na porównywaniu operatorem == napisów w Javie;) Ot, takie przyzwyczajenie z C#
Ta pierwsza właściwość C++ od zawsze strasznie mnie denerwowała. Co gorsze, nie wiedziałem, że łączenie stałych stringów w zaprezentowany sposób (“ala” “ma” “kota”) jest w ogóle dopuszczalne, co zmuszało mnie do tworzenia potworków w tylu:
DoSomething((std::string("ala") + "ma" + "kota").c_str());
Akurat jakkolwiek w C++ może się to wydawać niewygodne, to jednak jest to bardzo fajna cecha języka, że siedzisz blisko reprezentacji danych w pamięci.
Jeśli potrzebujesz większej abstrakcji to lepiej rozważyć inny język, np. C#.
Xion, co to jest to ostatnie? Ostatnio, jak sprawdzałem, to każdą nową zmienną deklarowało się w ecmascriptach słówkiem “var” :)
Notka o Pythonie też zła: jeżeli będziesz iterował w sposób, jaki pokazałeś, to będzie to *zwykła iteracja po kluczach* – a każdy klucz będzie następnie traktowany jako `iterable` i rozpakowywany do zmiennych (k,v).
@Kos: Fakt, masz rację, takie właśnie będzie zachowanie przy iterowaniu. Tak czy siak jest ono niezgodne z oczekiwanym :) (A tekst w notce oczywiście poprawiłem)