Pisanie solidnego kodu R: przestrzenie nazw, maskowanie i używanie operatora `::`

Krótka wersja

Dla tych, którzy nie chcą czytać mojego „przypadku”, to jest esencja:

Jaki jest zalecany sposób na zminimalizowanie szans, że nowe pakiety przełamają istniejący kod, tj. Wykonanie kodu, który piszeszjak najmocniejszy?

Jaki jest zalecany sposób najlepszego wykorzystaniamechanizm przestrzeni nazw gdy

a) po prostuza pomocą wniesione pakiety (powiedzmy w niektórych projektach R Analysis)?

b) w odniesieniu dorozwój własne pakiety?

Jak najlepiej unikać konfliktów w odniesieniu dozajęcia formalne (przeważnieKlasy referencyjne w moim przypadku), ponieważ nie ma nawet mechanizmu przestrzeni nazw porównywalnego z:: na zajęcia (AFAIU)?

Sposób działania wszechświata R

To jest coś, co dręczyło mnie od dwóch lat, ale nie czuję się tak, jakbym przyszedł do satysfakcjonującego rozwiązania. Plus czuję, że jest coraz gorzej.

Widzimy coraz większą liczbę pakietówCRAN, github, R-Kuźnia i tym podobne, co jest po prostu wspaniałe.

W takim zdecentralizowanym środowisku naturalne jest, że podstawa kodu tworząca R (powiedzmy, że jestpodstawa R iprzyczynił się Rdla uproszczenia) będzie odbiegać od idealnego stanu w odniesieniu do solidności: ludzie przestrzegają różnych konwencji, istnieją klasy referencyjne S3, S4, S4 itd. Rzeczy nie mogą być tak „wyrównane”, jak gdyby były „centralna instancja rozliczeniowa„To wymusiło konwencje.

Problem

Biorąc powyższe pod uwagę, może być bardzo trudno użyć R do napisania solidnego kodu. Nie wszystko, czego potrzebujesz, będzie w bazie R. W przypadku niektórych projektów zostanie załadowanych kilka pakietów.

IMHO, największym problemem w tym względzie jest sposób, w jaki koncepcja przestrzeni nazw jest używana w R: R pozwala po prostu napisać nazwę pewnej funkcji / metody bez wyraźnego wymagania jej przestrzeni nazw (tj.foo vs.namespace::foo).

Dla uproszczenia wszyscy tak robią. Ale w ten sposób konflikty nazw, zepsuty kod i konieczność przepisania / zmiany kodu to tylko kwestia czasu (lub liczby załadowanych pakietów).

W najlepszym razie to zrobiszwiedzieć o tym, które istniejące funkcje są maskowane / przeciążane przez nowo dodany pakiet. W najgorszym razie nie będziesz miał pojęcia, dopóki nie złamiesz kodu.

Kilka przykładów:

spróbuj załadowaćRMySQL iRSQLite jednocześnie nie idą zbyt dobrzerównieżRMongo nadpisze niektóre funkcjeRMySQLprognoza maskuje wiele rzeczy w odniesieniu do funkcji związanych z ARIMAR.utils nawet maskujebase::parse rutyna

(Nie mogę sobie przypomnieć, które funkcje w szczególności powodowały problemy, ale jestem skłonny ponownie sprawdzić, czy są jakieś zainteresowania)

Co zaskakujące, nie wydaje się to przeszkadzać wielu programistom. Kilka razy próbowałem wzbudzić zainteresowanier-devel, bez znaczącego efektu.

Wady korzystania z:: operatorUżywając:: operator może znacząco zaszkodzić wydajności w pewnych kontekstach, jak Dominick Samperiwskazany.Gdyrozwój własny pakiet, nie możesz nawet użyć:: operator w całym twoim kodzie, ponieważ twój kod nie jest jeszcze prawdziwym pakietem, a zatem nie ma jeszcze przestrzeni nazw. Więc musiałbym początkowo trzymać sięfoo sposób, buduj, testuj, a następnie wróć do zmiany wszystkiego nanamespace::foo. Nie całkiem.Możliwe rozwiązania, aby uniknąć tych problemówZmień przypisanie każda funkcja z każdego pakietu do zmiennej zgodnej z pewnymi konwencjami nazewnictwa, np.namespace..foo w celu uniknięcia nieefektywności związanych znamespace::foo (Zarysowałem to raztutaj). Plusy: to działa. Wady: jest niezdarny i podwajasz pamięć.Symulować przestrzeń nazw podczas tworzenia pakietu. AFAIU, to nie jest możliwe, przynajmniej ja byłempowiedziano to wtedy.Zrób toobowiązkowy używaćnamespace::foo. IMHO, to byłaby najlepsza rzecz do zrobienia. Jasne, stracilibyśmy trochę prostoty, ale znowu wszechświat R po prostu nie jest już prosty (przynajmniej nie jest tak prosty jak na początku lat 00).A co z (formalnymi) zajęciami?

Oprócz aspektów opisanych powyżej:: sposób działa całkiem dobrze dla funkcji / metod. Ale co z definicjami klas?

Weź paczkęData i godzina z jego klasątimeDate. Powiedz, że przychodzi kolejny pakiet, który również ma klasętimeDate. Nie widzę, jak mógłbym wyraźnie stwierdzić, że chciałbym nową instancję klasytimeDate z jednego z dwóch pakietów.

Coś takiego nie zadziała:

new(timeDate::timeDate)
new("timeDate::timeDate")
new("timeDate", ns="timeDate")

Może to być ogromny problem, ponieważ coraz więcej osób przełącza się na styl OOP dla swoich pakietów R, co prowadzi do wielu definicji klas. Jezeli tamjest sposób jawnego adresowania przestrzeni nazw definicji klasy, bardzo bym docenił wskaźnik!

Wniosek

Mimo że było to trochę długie, mam nadzieję, że udało mi się wskazać podstawowy problem / pytanie i że mogę podnieść tu więcej świadomości.

Myślędevtools imvbutils czy masz pewne podejścia, które mogą być warte rozpowszechnienia, ale jestem pewien, że jest więcej do powiedzenia.

questionAnswers(2)

yourAnswerToTheQuestion