R 4.4.0: Was ist neu?

R Version 4.4.0 enthält einige Neuerungen: elegante NULL-Abfragen mit %||% aus rlang, speichereffiziente rekursive Funktionen, Sicherheitspatch beim RDS-Format, und mehr. Fast zeitgleich erschien RStudio 2024.04.0.

Am 24. April 2024 wurde R-Version 4.4.0 veröffentlicht.

Was ist neu – lohnt es sich, sofort umzusteigen?

%||% Verwende x; außer x ist NULL: Dann y

In Datenanalysen findet man häufig Code wie diesen:

if (is.null(x)) y else x

# Variante
if (!is.null(x)) x else y

Das rlang-Paket, das bei Endnutzern bei weitem nicht so bekannt ist wie die Kern-Pakete des tidyverse, bietet dazu seit längerem eine elegante Alternative:

x %||% y

Über 180 R-Pakete binden rlang ein (als sog. dependency), darunter so bekannte Schwergewichte wie tidyverse, dplyr, ggplot2, shiny, DT, leaflet, rmarkdown, webshot2, Rcmdr (R Commander), quarto und viele andere. Siehe:

tools::dependsOnPkgs("rlang")

Hadley Wickham wurde mal gefragt, warum er R durch Erweiterungspakete weiterentwickle – wäre es nicht toll, wenn Base R, die Basisinstallation, so nützliche Funktionalitäten biete wie das tidyverse? Sinngemäße Antwort: Base R wird viel konservativer weiterentwickelt, da ein hohes Risiko sogenannter breaking changes besteht, d. h. dass Code, der bisher funktionierte, Fehler wirft oder, eventuell schlimmer, zu unerwarteten Ergebnissen führt. Bei Erweiterungspaketen sind die Hürden weitaus geringer. Alter (Base R-) Code ist nicht betroffen; wer neue Funktionalitäten nutzen möchte, greift auf die Pakete zu.

Es gibt jedoch seltene Ausnahmen, in denen Funktionen aus Erweiterungspaketen in Base R übernommen werden.

Beispiele:

Und nun gibt es ein weiteres Beispiel: %||% ist seit R 4.4.0 Bestandteil von Base R. Alle diese Fälle kann man getrost als große Erfolge der jeweiligen Paket-Autoren verbuchen!

Tailcall: Speichereffiziente rekursive Funktionen

Rekursive Funktionen sind eine praktische Programmiertechnik: Dabei ruft eine Funktion sich selbst auf, wenn eine Lösung iterativ gefunden werden muss. Beispiel:

ueberlauf <- function(n, max_iter) {
   if (n >= max_iter) {
      return("Fertsch!")
   }
   ueberlauf(n + 1, max_iter)
}

ueberlauf(1, max_iter = 100)
[1] "Fertsch!"

ueberlauf() ruft sich selbst auf, bis die maximale Anzahl an Iterationen abgearbeitet ist.

Setzt man die Zahl zu hoch, gibt es eine Fehlermeldung, die an die bekannte Seite für Programmier-Lösungen erinnert:

ueberlauf(1, max_iter = 1e5)

Error in ueberlauf(n + 1, max_iter) : node stack overflow
Error during wrapup: node stack overflow
Error: no more error handlers available (recursive errors?); invoking 'abort' restart

Bei jedem Selbst-Aufruf der Funktion wird der Call Stack, der „Stapel“ für die Verwaltung des Programmablaufs erweitert und die aufrufende Funktionsumgebung gespeichert. Bei einer hohen Anzahl genisteter Funktionsaufrufe wird das speicher-intensiv und kann zum Abbruch mit obiger Fehlermeldung führen.

R 4.4.0 bietet eine (experimentelle!) Lösung an: In Fällen wie dem obigen ist es nicht nötig, die gesamte Geschichte der bisherigen Funktionsaufrufe zu bewahren; stattdessen genügt es, den vorigen Funktionsaufruf durch den neuen zu ersetzen – ohne zusätzlichen Speicherbedarf. Etwa so:

ueberlauf <- function(n, max_iter) {
   if (n >= max_iter) {
      return("Fertsch!")
   }
   Tailcall(ueberlauf, n + 1, max_iter)
}

ueberlauf(1, max_iter = 1e5)
[1] "Fertsch!"

Durch die in R4.4.0 neu eingeführte Tailcall-Funktion wird der Speicher bei rekursiven (sich selbst aufrufenden) Funktionen wesentlich effizienter genutzt, die Fehlermeldung tritt nicht auf, der Call Stack bleibt schlank.

Achtung: innerhalb von Tailcall steht der Funktionsname ueberlauf ohne die sonst üblichen Klammern, also nicht ueberlauf(n + 1, …)!

Ausführlicher beschrieben in einem Blogartikel von Jumping Rivers.

R 4.4.0: Sicherheitslücke bei RDS-Dateien geschlossen!

Ein wesentlicher Grund, schnellstmöglich auf R 4.4.0 zu aktualisieren, liegt in einer damit geschlossenen Sicherheitslücke bei RDS-Dateien.

In R können Objekte mittels saveRDS() serialisiert und mit readRDS() de-serialisiert (geladen) werden. Dieses Format ist auch im Spiel, wenn R-Pakete gespeichert und geladen werden. Das HiddenLayer-Team fand eine Sicherheitslücke, CVE-2024-27322, die es ermöglichte, mit RDS-Dateien Schadcode auszuführen. Szenarien, in denen ein solcher Missbrauch auftreten kann:

  • Shiny Apps, in die .rds-Dateien hochgeladen werden
  • R-Pakete, auch auf CRAN, die beim Laden Schadcode ausführen!

R 4.4.0 unterbindet dies in einigen Fällen.

Ivan Krylov zeichnet ein differenzierteres Bild und beschreibt einige Möglichkeiten, wie Schadcode in R eingeschleust werden kann. Er sieht dies nicht als Sicherheitslücke, sondern als normalen Zustand, der kaum generell zu unterbinden ist. Den Bericht von HiddenLayer bezeichnet er als PR-Trick. Sogar beim simplen CSV-Format sind „Injections“, Code-Attacken möglich. Serialisation und De-Serialisation sind nicht als ultimative Schutzmauer gegen Code-Attacken gedacht.

Neues zu R 4.4.0 – Literatur, Details:

Ähnlicher früherer Artikel: R 4.1.0: Base R Pipe! |>

Ebenfalls neu: RStudio 2024.04.0

RStudio erhielt kürzlich ebenfalls ein Update. Unter anderem enthält es nun die neue Quarto-Version 1.4 (mit Dashboards!) sowie Unterstützung für Shiny für Python.

Viel Erfolg mit R! Wenn ich Sie mit Workshops / Seminaren / Webinaren unterstützen kann, freue ich mich auf Kontaktaufnahme.

Freue mich über Kommentare!

Wir benutzen Cookies um die Nutzerfreundlichkeit der Webseite zu verbessen. Durch Deinen Besuch stimmst Du dem zu.