Grupos de Google ya no admite nuevas publicaciones ni suscripciones de Usenet. El contenido anterior sigue siendo visible.

TypeScript - jak uzyskać zmienne prywatne? Gdzie korzyści z TS?

Visto 5 veces
Saltar al primer mensaje no leído

Marek S

no leída,
4 sept 2019, 16:11:124/9/19
a
Witam,

Biję się z myślami czy nie przesiąść się z JS ES6 na TypeScript. Właśnie
testuję pod PHPStorm'em edycję i transkompilację TS i działa ten
mechanizm wyśmienicie. Ucieszony tym zabrałem się za pierwszy skrypt i
... poległem na podstawach. Stworzyłem dwie klasy jako moduły) Test i Test2:

abstract class Test {
private _message: string;

protected printMessage() {
console.log(this._message);
}

protected constructor(message: string) {
this._message = message;

}
}

export default Test;

*****************************************

import Test from "./Test";

class Test2 extends Test{
private _message: string;

constructor(message:string) {
super("dupa");
this._message = message;
}

execute() {
console.log(this._message);
this.printMessage();
}
}

let demo = new Test2("my message");
demo.execute();

Zadeklarowałem _message jako zmienną prywatną w obu klasach i... powstał
konflikt! Transkompilator nie poradził sobie z tym. Oczekiwałbym
samoczynnej zmiany nazwy funkcji by w wyjściowym JS nie było konfliktów.
Zatem jak żyć? :-) To samo dotyczy metod. Te prywatne zwalczają się
zamiast być niezależnymi w każdej z klas.

Póki co nie dostrzegam wielkich korzyści z przejścia na TS. Aby uzyskać
wpełni prywatne zmienne, muszę ręcznie rzeźbić kod na symbolach - jak w
natywnym JS. Jedynie IDE nieco ułatwi programowanie ukrywając to, co
prywatne i czasem przypilnuje typów (ale tylko przy jawnych
podstawieniach). Czy zatem warto bawić się w TS?

--
Pozdrawiam,
Marek

Szyk Cech

no leída,
4 sept 2019, 23:54:484/9/19
a
Na pewno wiesz co robisz?
_message raczej powinno być tylko jedno w obu klasach. Dziedziczenie
polega na tym, że od przodka wjeżdża wszystko.
Inny problem jest taki, że _message jest prywatna. W C++ oznacza to, że
nie jest ona dostępna dla potomków. W takiej sytuacji gdy ma być ona
dostępna również dla potomka sugerowałbym dyrektywę protected jeśli coś
takiego w ogóle jest w tym języku (protected stosuję w C++).

Roman Tyczka

no leída,
5 sept 2019, 3:50:595/9/19
a
Nie żabym się znał na TS, choć mam w planie nim się zająć, ale tak na
logikę to zastanawia mnie które _message wg Ciebie miałaby wziąć metoda
printMessage() wywołana z klasy Test2? Dla mnie to ewidentny konflikt.


--
pozdrawiam
Roman Tyczka

Marek S

no leída,
5 sept 2019, 13:43:555/9/19
a
W dniu 2019-09-05 o 09:50, Roman Tyczka pisze:
>
> Nie żabym się znał na TS, choć mam w planie nim się zająć, ale tak na
> logikę to zastanawia mnie które _message wg Ciebie miałaby wziąć metoda
> printMessage() wywołana z klasy Test2? Dla mnie to ewidentny konflikt.
>

Kurcze, jesteś drugą osobą, która o to dziś mnie pyta. Dla mnie sprawa
jest tak oczywista jak oddychanie. Napisz sobie skrypt w PHP o podobnej
strukturze i tam dostaniesz odpowiedź. Jeśli nie PHP, to może C#. Jeśli
miałbym tworzyć standardy, to z pewnością powieliłbym zachowanie się
prywatnych zmiennych z tego typu języków.

Reasumując, metoda printMessage() powinno zwrócić wartość "dupa".
Istnienie identycznej zmiennej prywatnej w klasie potomnej nie ma prawa
nadpisywać tego, co jest w bazowej.

Przedstaw mi swój tok rozumowania, który powoduje, że masz wątpliwości.
Ciekawi mnie ich źródło.

--
Pozdrawiam,
Marek

Marek S

no leída,
5 sept 2019, 13:58:355/9/19
a
W dniu 2019-09-05 o 05:54, Szyk Cech pisze:

> Na pewno wiesz co robisz?

Wydaje mi się, że tak. Od lat programuję w natywnym JS.

> _message raczej powinno być tylko jedno w obu klasach. Dziedziczenie
> polega na tym, że od przodka wjeżdża wszystko.
> Inny problem jest taki, że _message jest prywatna.

No i o tym problemie mowa. W natywnym JS ES6 nie mam problemu z
tworzeniem zmiennych prywatnych, a i metod też - choć ponoć takowe nie
istnieją. TS już tego nie potrafi więc w tym zakresie kuleje. Oto przykład:

Moduł 1:

let privateMethod = Symbol();
let privateVar = Symbol();

class a {
constructor() {
this[privateVar]=5;
}

this[privateMethod]() {
console.log(this[privateVar]);
}

printA() {
this[privateMethod]();
}

}

Moduł 2:

import a from ...

let privateMethod = Symbol();
let privateVar = Symbol();

class b extends a {
constructor() {
this[privateVar]=10;
}

printB() {
this.printA();
console.log(this[privateVar]);
}

}

let obj = new b();
obj.printB(); // metoda publiczna

// 5
// 10

obj.printA(); //metoda publiczna

//5

obj[privateMethod](); //metoda prywatna

//error

W powyższym przykładzie privateVar jest prawdziwie prywatne dla obu
klas. Wywołanie prywatnej metody privateMethod kończy się błędem. Da się
to zrobić w ES6? Da się! A TypeScript wymięka. A wystarczyłoby aby
transkodował prywatne zmienne i metody do konstrukcji z wykorzystaniem
symboli.

Kod pisałem z palca - więc mogłem jakieś błędy popełnić.

--
Pozdrawiam,
Marek

Marek S

no leída,
5 sept 2019, 14:21:305/9/19
a
Korekta. Już zauważyłem błąd. Zamiast:

>   this[privateMethod]() {
>     console.log(this[privateVar]);
>   }

Miało być:

[privateMethod]() {
console.log(this[privateVar]);
}

Jeśli jeszcze jakiś błąd będzie, to z góry przepraszam.

--
Pozdrawiam,
Marek

Tomek

no leída,
6 sept 2019, 7:56:076/9/19
a
W dniu 05.09.2019 o 19:43, Marek S pisze:
> W dniu 2019-09-05 o 09:50, Roman Tyczka pisze:
>>
>> Nie żabym się znał na TS
>
> Przedstaw mi swój tok rozumowania, który powoduje, że masz wątpliwości.
> Ciekawi mnie ich źródło.
>

Też pojęcia nie mam o TS ale w JS jeśli wewnątrz funkcji jest
wykorzystywane "this" to te "this" może znaczyć coś kompletnie innego w
zależności od kontekstu jak jest wywoływana ta funkcja.

Marek S

no leída,
6 sept 2019, 8:57:216/9/19
a
W dniu 2019-09-06 o 13:55, Tomek pisze:

> Też pojęcia nie mam o TS ale w JS jeśli wewnątrz funkcji jest
> wykorzystywane "this" to te "this" może znaczyć coś kompletnie innego w
> zależności od kontekstu jak jest wywoływana ta funkcja.
>

Ok, ale ja nie o tym. Po pierwsze ustalmy, że nie chodzi o funkcje ale o
klasy (słowo kluczowe class). Słowo kluczowe this w każdej metodzie
klasy znaczy dokładnie to samo i ma zasięg całej klasy.

A tematem rozmowy jest to, że w natywnym JS da się, choć nie pięknie,
zdefiniować prywatne metody i właściwości. Natomiast w TS, prywatne
zmienne są wpół prywatne. Transkompilator, podczas zamiany TS w JS, nie
radzi sobie z przekształceniem prywatnych elementów do postaci JS, w
taki sposób, by prywatność zachować. Zamiast tego wyświetla error
mówiący o tym, że zmienna prywatna w klasie potomnej pokrywa się ze
zmienną prywatną w klasie bazowej - co spowoduje konflikt. I faktycznie
wynikowy kod JS nie będzie działał w takim przypadku.

Konkluzja jest taka, że TS jest przydatny, ale wobec takiej niedoróby,
póki co trzymam się natywnego JS. Jakoś mi się to wydaje
nieprawdopodobne aby twórcy TS to przeoczyli. Dlatego podpytuję tutaj o
to czy jest jakieś obejście problemu.

--
Pozdrawiam,
Marek

Roman Tyczka

no leída,
7 sept 2019, 10:12:447/9/19
a
On Thu, 5 Sep 2019 19:43:52 +0200, Marek S wrote:

>> Nie żabym się znał na TS, choć mam w planie nim się zająć, ale tak na
>> logikę to zastanawia mnie które _message wg Ciebie miałaby wziąć metoda
>> printMessage() wywołana z klasy Test2? Dla mnie to ewidentny konflikt.
>>
>
> Kurcze, jesteś drugą osobą, która o to dziś mnie pyta. Dla mnie sprawa
> jest tak oczywista jak oddychanie. Napisz sobie skrypt w PHP o podobnej
> strukturze i tam dostaniesz odpowiedź.

Ja nie napisałem, że nie znam odpowiedzi w innych językach, napisałem, że
dla mnie to nie jest oczywiste jak Ci się wydaje.

> Jeśli nie PHP, to może C#. Jeśli
> miałbym tworzyć standardy, to z pewnością powieliłbym zachowanie się
> prywatnych zmiennych z tego typu języków.

To, że w jakichś językach jest to tak czy inaczej nie jest dowodem, że tak
powinno być.

> Reasumując, metoda printMessage() powinno zwrócić wartość "dupa".
> Istnienie identycznej zmiennej prywatnej w klasie potomnej nie ma prawa
> nadpisywać tego, co jest w bazowej.
>
> Przedstaw mi swój tok rozumowania, który powoduje, że masz wątpliwości.
> Ciekawi mnie ich źródło.

Źródłem są przemyślenia. Oto mój tok rozumowania:
Tworzysz obiekt klasy Test2. Klasa Test2 ma prywatne pole ukryte pod
this._message. Wołasz z tego obiektu metodę, która zwraca this._message.
Skoro jest to obiekt klasy Test2 to dla tego typu this._message jest czymś
innym niż dla typy Test, prawda? Dla mnie to sprawa oczywista jak
oddychanie ;-) Jest tu wyraźna niejednoznaczność i punkt sporny, który
warto wywalić na twarz chociażby ostrzeżeniem.

To, że Java czy C# zwraca bezrefleksyjnie (czy są jakieś ostrzeżenia
kompilatora?) wcale nie jest fajne, bo łatwo o masę głupich błędów, które
transpiler TS wyłapuje jak zeznałeś. Mnie to bardzo cieszy, bo nie uważam,
że taka praktyka jak identyczna nazwa prywatnego pola w dziedziczeniu to
dobra praktyka. Ot wszystko.


--
pozdrawiam
Roman Tyczka

Marek S

no leída,
7 sept 2019, 18:07:437/9/19
a
W dniu 2019-09-07 o 16:12, Roman Tyczka pisze:

>
>> Jeśli nie PHP, to może C#. Jeśli miałbym tworzyć standardy, to z
>> pewnością powieliłbym zachowanie się prywatnych zmiennych z tego
>> typu języków.
>
> To, że w jakichś językach jest to tak czy inaczej nie jest dowodem,
> że tak powinno być.

Chwila, ale nie rozmawiamy tu o postępowaniu sądowym, czy rozkminianiu
zagadek matematycznych by o jakichś dowodach wspominać.

Jeśli chcesz bawić się w dowody zachowania się zmiennych prywatnych w
JS, to z natury rzeczy stoisz na przegranej pozycji, bo czegoś takiego w
JS nie ma ... przynajmniej do momentu gdy zastosujemy sztuczek, jakie
opisałem. Wtedy można je wykrzesać nawet w natywnym JS i zachowują się
one dokładnie tak samo jak w innych językach.

Jeśli natomiast mówimy o zachowaniu się zmiennych prywatnych w TS to
może warto wrócić do podstaw i przeczytać definicję zmiennej prywatne.
Jej definicja jest jedna i wspólna dla wszystkich języków:

https://pl.wikipedia.org/wiki/Zmienna_prywatna

lub tu:

https://pl.wikipedia.org/wiki/Zmienna_(informatyka)

"Zmienne zadeklarowane w module mogą być zmiennymi prywatnymi modułu –
dostępnymi wyłącznie z jego wnętrza – lub zmiennymi publicznymi
(eksportowanymi) – dostępnymi tam, gdzie moduł jest wykorzystywany.
Podobnie jest ze zmiennymi w klasie – mogą być dostępne:
tylko dla danej klasy (zmienna prywatna),"

https://www.p-programowanie.pl/cpp/klasy-c/

"private – dostęp do składników klasy jest zabroniony z poza ciała klasy"

Nie chcę już cytować linków na ten sam temat w kontekście PHP czy Java.
Sposób zachowania zmiennych prywatnych jest tam również zgodny z definicją.

TS łamie tą definicję. Zdefiniowana przez niego zmienna prywatna w
klasie, w kodzie wynikowym będzie podlegać nadpisywaniu przez klasę
potomną. Owszem, powstanie podczas transkompilacji absurdalny błąd,
który nie ma prawa zaistnieć, a wadliwy kod wynikowy i tak wygeneruje się.

> Źródłem są przemyślenia. Oto mój tok rozumowania: Tworzysz obiekt
> klasy Test2. Klasa Test2 ma prywatne pole ukryte pod this._message.
> Wołasz z tego obiektu metodę, która zwraca this._message. Skoro jest
> to obiekt klasy Test2 to dla tego typu this._message jest czymś innym
> niż dla typy Test, prawda? Dla mnie to sprawa oczywista jak
> oddychanie ;-) Jest tu wyraźna niejednoznaczność i punkt sporny,
> który warto wywalić na twarz chociażby ostrzeżeniem.
>
> To, że Java czy C# zwraca bezrefleksyjnie (czy są jakieś ostrzeżenia
> kompilatora?) wcale nie jest fajne, bo łatwo o masę głupich błędów,
> które transpiler TS wyłapuje jak zeznałeś. Mnie to bardzo cieszy, bo
> nie uważam, że taka praktyka jak identyczna nazwa prywatnego pola w
> dziedziczeniu to dobra praktyka. Ot wszystko.
>

Hmmm... wydaje mi się, że taki sposób rozumowania i obawy o to, co jak
mają się zachowywać zmienne prywatne (niezależnie od języka
programowania) wynikają z Twojego niezrozumienia czym w ogóle są zmienne
prywatne. Zapewniam Cię, że ani w C ani w PHP obecność zmiennej
prywatnej w klasie bazowej nie będzie podlegać nadpisaniu w klasie
potomnej bo to są dwa oddzielne byty w dwóch różnych obszarach RAM.
Żadne ostrzeżenia o używaniu zmiennych prywatnych w obu klasach nie
powstaną w trakcie kompilacji C lub używania PHP bo ... nie ma o czym
ostrzegać. Nie ma w tym żadnego błędu jak i obie zmienne nie będą w
konflikcie. Jedynie TS się wyłamuje i nadużywa terminu prywatności.
Przypuszczam, że jest to zwyczajny błąd twórców TS.

Spytam jeszcze: czy Ty w ogóle programujesz z użyciem OOP? Masz
wątpliwości co do najbardziej podstawowych pojęć w tej technice.

--
Pozdrawiam,
Marek
0 mensajes nuevos