Zachowanie jest bardzo podobne do Array.Resize
metody w .NET. Aby zrozumieć, co się dzieje, pomocne może być przejrzenie historii .
tokena w C, C ++, Java, C # i Swift.
W C struktura jest niczym więcej niż agregacją zmiennych. Zastosowanie .
do zmiennej typu struktury spowoduje dostęp do zmiennej przechowywanej w strukturze. Wskaźniki do obiektów nie przechowują agregacji zmiennych, ale je identyfikują . Jeśli ktoś ma wskaźnik, który identyfikuje strukturę, ->
operator może być wykorzystany do uzyskania dostępu do zmiennej przechowywanej w strukturze identyfikowanej przez wskaźnik.
W C ++ struktury i klasy nie tylko agregują zmienne, ale także mogą do nich dołączać kod. Użycie .
do wywołania metody spowoduje, że zmienna poprosi tę metodę o działanie na zawartość samej zmiennej ; użycie ->
zmiennej identyfikującej obiekt spowoduje, że ta metoda będzie działać na obiekt zidentyfikowany przez zmienną.
W Javie wszystkie niestandardowe typy zmiennych po prostu identyfikują obiekty, a wywołanie metody na zmiennej powie metodzie, który obiekt jest identyfikowany przez zmienną. Zmienne nie mogą bezpośrednio przechowywać żadnego rodzaju złożonego typu danych, ani nie ma żadnych środków, za pomocą których metoda może uzyskać dostęp do zmiennej, na której jest wywoływana. Ograniczenia te, chociaż semantycznie ograniczające, znacznie upraszczają środowisko wykonawcze i ułatwiają sprawdzanie poprawności kodu bajtowego; takie uproszczenia zmniejszyły nakłady związane z Javą w czasie, gdy rynek był wrażliwy na takie problemy, a tym samym pomogły jej zdobyć przyczepność na rynku. Oznaczały także, że nie było potrzeby używania tokena równoważnego z .
używanym w C lub C ++. Chociaż Java mogła być używana ->
w taki sam sposób jak C i C ++, twórcy zdecydowali się na użycie jednego znaku.
ponieważ nie był potrzebny do żadnego innego celu.
W języku C # i innych językach .NET zmienne mogą albo identyfikować obiekty, albo bezpośrednio przechowywać złożone typy danych. W przypadku użycia zmiennej o złożonym typie danych .
działa na zawartość zmiennej; zastosowany do zmiennej typu odniesienia .
działa na zidentyfikowany obiektprzez to. W przypadku niektórych rodzajów operacji rozróżnienie semantyczne nie jest szczególnie ważne, ale w przypadku innych jest tak. Najbardziej problematyczne są sytuacje, w których metoda złożonego typu danych, która zmodyfikowałaby zmienną, na której jest wywoływana, jest wywoływana na zmiennej tylko do odczytu. Jeśli zostanie podjęta próba wywołania metody na wartości lub zmiennej tylko do odczytu, kompilatory zazwyczaj skopiują zmienną, pozwól metodzie na nią zareagować i odrzuć zmienną. Jest to ogólnie bezpieczne w przypadku metod, które tylko odczytują zmienną, ale nie jest bezpieczne w przypadku metod, które do niej piszą. Niestety, .does nie ma jak dotąd żadnych środków wskazujących, które metody można bezpiecznie zastosować z takim zastąpieniem, a które nie.
W Swift metody agregujące mogą wyraźnie wskazać, czy zmodyfikują zmienną, na której są wywoływane, a kompilator zabrania używania metod mutacji zmiennych tylko do odczytu (zamiast zmutować tymczasowe kopie zmiennej, które następnie wyrzucić). Z powodu tego rozróżnienia używanie .
tokena do wywoływania metod modyfikujących zmienne, na które są wywoływane, jest znacznie bezpieczniejsze w Swift niż w .NET. Niestety fakt, że .
do tego celu wykorzystywany jest ten sam token, który działa na obiekt zewnętrzny zidentyfikowany przez zmienną, oznacza, że istnieje możliwość pomyłki.
Gdyby dysponował maszyną czasu i wrócił do tworzenia C # i / lub Swift, można by z mocą wsteczną uniknąć wielu nieporozumień związanych z takimi problemami, ponieważ języki używają tokenów .
i ->
w sposób znacznie zbliżony do użycia C ++. Metody zarówno agregatów, jak i typów referencyjnych mogłyby posłużyć .
do działania na zmienną, na której zostały wywołane, i ->
na wartość (dla kompozytów) lub na rzecz zidentyfikowanej w ten sposób (dla typów referencyjnych). Żaden język nie jest jednak tak zaprojektowany.
W języku C # normalną praktyką dla metody modyfikacji zmiennej, na której jest ona wywoływana, jest przekazywanie zmiennej jako ref
parametru do metody. W ten sposób wywołanie Array.Resize(ref someArray, 23);
podczas someArray
identyfikacji tablicy 20 elementów spowoduje someArray
zidentyfikowanie nowej tablicy 23 elementów, bez wpływu na tablicę oryginalną. Użycie parametru ref
wyjaśnia, że należy oczekiwać, że metoda zmodyfikuje zmienną, na której jest wywoływana. W wielu przypadkach korzystna jest możliwość modyfikowania zmiennych bez konieczności używania metod statycznych; Szybkie adresy, co oznacza przy użyciu .
składni. Wadą jest to, że traci wyjaśnienie, jakie metody działają na zmienne, a które na wartości.