Написание надежного R-кода: пространства имен, маскирование и использование оператора `::`

Short version

Для тех, кто не хочет читать мой "случай", это суть:

What is the recommended way of minimizing the chances of new packages breaking existing code, i.e. of making the code you write as robust as possible?

What is the recommended way of making the best use of the namespace mechanism when

a) just using contributed packages (say in just some R Analysis Project)?

b) with respect to developing own packages?

How best to avoid conflicts with respect to formal classes (mostly Reference Classes in my case) as there isn't even a namespace mechanism comparable to :: for classes (AFAIU)?

The way the R universe works

Это то, что мучает меня в голове уже около двух лет, но я не чувствую, как будто я нашел удовлетворительное решение. Плюс, я чувствую, что все ухудшается.

Мы видим все большее количество пакетов наCRAN, GitHub, Р-Фордж и тому подобное, что просто потрясающе.

В такой децентрализованной среде естественно, что кодовая база, которая составляет R (скажем, чтоbase R а такжеcontributed R(для простоты) будет отклоняться от идеального состояния в отношении устойчивости: люди следуют различным соглашениям, существуют эталонные классы S3, S4, S4 и т. д. Вещи могут быть «выровненными». как было бы, если бы был & quot;central clearing instance& Quot; что соблюдаются конвенции. Это нормально.

The problem

Учитывая вышесказанное, может быть очень сложно использовать R для написания надежного кода. Не все, что вам нужно, будет в базе R. Для определенных проектов вам придется загружать довольно много пакетов.

IMHO, the biggest issue in that respect is the way the namespace concept is put to use in R: R allows for simply writing the name of a certain function/method without explicitly requiring it's namespace (i.e. foo vs. namespace::foo).

Итак, ради простоты, это то, что все делают. Но таким образом, конфликты имен, неработающий код и необходимость переписать / реорганизовать ваш код - это вопрос времени (или количества загруженных различных пакетов).

В лучшем случае вы будетеknow о том, какие существующие функции маскируются / перегружаются вновь добавленным пакетом. В худшем случае у вас не будет никакой подсказки, пока ваш код не сломается.

Пара примеров:

try loading RMySQL and RSQLite at the same time, they don't go along very well also RMongo will overwrite certain functions of RMySQL forecast masks a lot of stuff with respect to ARIMA-related functions R.utils even masks the base::parse routine

(Я не могу вспомнить, какие функции, в частности, вызывали проблемы, но я хочу снова посмотреть, если есть интерес)

Удивительно, но это, похоже, не беспокоит многих программистов. Я пытался повысить интерес пару раз вг-Devel, без особой пользы.

Downsides of using the :: operator Using the :: operator might significantly hurt efficiency in certain contexts as Dominick Samperi pointed out. When developing your own package, you can't even use the :: operator throughout your own code as your code is no real package yet and thus there's also no namespace yet. So I would have to initially stick to the foo way, build, test and then go back to changing everything to namespace::foo. Not really. Possible solutions to avoid these problems Reassign each function from each package to a variable that follows certain naming conventions, e.g. namespace..foo in order to avoid the inefficiencies associated with namespace::foo (I outlined it once here). Pros: it works. Cons: it's clumsy and you double the memory used. Simulate a namespace when developing your package. AFAIU, this is not really possible, at least I was told so back then. Make it mandatory to use namespace::foo. IMHO, that would be the best thing to do. Sure, we would lose some extend of simplicity, but then again the R universe just isn't simple anymore (at least it's not as simple as in the early 00's). And what about (formal) classes?

Помимо аспектов, описанных выше,:: путь работает довольно хорошо для функций / методов. Но как насчет определения классов?

Взять пакетtimeDate с этим классомtimeDate, Скажем, приходит другой пакет, который также имеет классtimeDate, Я не вижу, как я мог бы явно заявить, что я хотел бы новый экземпляр классаtimeDate из любого из двух пакетов.

Как то так не получится

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

Это может быть огромной проблемой, так как все больше и больше людей переключаются на OOP-стиль для своих пакетов R, что приводит к большому количеству определений классов. Если тамis способ явно обратиться к пространству имен определения класса, я был бы очень признателен за указатель!

Conclusion

Несмотря на то, что это было довольно долго, я надеюсь, что смог указать на основную проблему / вопрос и повысить осведомленность здесь.

Я думаюDevTools а такжеmvbutils У меня есть некоторые подходы, которые стоит распространять, но я уверен, что есть еще что сказать.

Ответы на вопрос(2)

Ваш ответ на вопрос