Giter VIP home page Giter VIP logo

bypass's Introduction

bypass

{bypass} provides a way to use the default behavior of internal generics, bypassing the S3 methods. This makes working with objects at the low level much easier and safer.

We provide counterparts to existing functions:

{base} {bypass}
c .c
dim .dim
dim<- .dim<-
$ .dollar
$<- .dollar<-
lapply .lapply
length .length
lengths .lengths
names .names
names<- .names<-
sapply .sapply
[ .subset1
[<- .subset1<-
[[<- .subset2<-
unlist .unlist

Note that base R already has .subset2() as a low level counterpart to [[. .subset1() is different from .subset() because it doesn’t lose attributes other than names and works on matrices. .dollar() is a wrapper around .subset2() so we also lose the partial matching of the original $ function.

Other functions are provided :

  • with_bypass() allows you to type the base versions in the .expr argument and get the bypass behavior
  • local_bypass() does the same but locally for the function in which it’s called
  • global_bypass() does this for a full package, it’s meant to be used in .onLoad()
  • with_dispatch() and local_dispatch() are the reverse of with_bypass() and local_bypass(), they re-enable dispatch when it’s been disabled by the other functions.

These are especially useful useful for [<- and [[<- which are tricky to use at the low level, as they need a lot of unclassing/reclassing.

Installation

Install with:

pak::pak("cynkra/bypass")

Example 1

At the high level POSIXlt objects look like simple vectors, and behave that way:

library(bypass)
x <- as.POSIXlt(c("2024-01-01", "2024-01-02"))
length(x)
#> [1] 2
names(x)
#> NULL

But in fact “POSIXlt” objects are not atomic vectors but named lists of vectors, S3 methods, for length(), names(), and more, are defined so we can treat them just like vectors.

Here’s another way we might have used to define the above object:

list(
  sec = c(0, 0),
  min = c(0L, 0L),
  hour = c(0L, 0L),
  mday = 1:2,
  mon = c(0L, 0L),
  year = c(124L, 124L),
  wday = 1:2,
  yday = 0:1,
  isdst = c(0L, 0L),
  zone = c("CET", "CET"),
  gmtoff = c(NA_integer_, NA_integer_)
) |>
  structure(class = c("POSIXlt", "POSIXt"), tzone = c("", "CET", "CEST"), balanced = TRUE)
#> [1] "2024-01-01 CET" "2024-01-02 CET"

The .length() and .names() functions can be used to access the low level length and names, these are roughly equivalent to length(unclass(x)) and names(unclass(x)) respectively, with special cases for environments.

.length(x)
#> [1] 11
.names(x)
#>  [1] "sec"    "min"    "hour"   "mday"   "mon"    "year"   "wday"   "yday"  
#>  [9] "isdst"  "zone"   "gmtoff"

The functions with_bypass(), local_bypass() and global_bypass() provide different ways to use the native syntax rather than dotted counterparts.

# with_bypass
with_bypass(names(x))
#>  [1] "sec"    "min"    "hour"   "mday"   "mon"    "year"   "wday"   "yday"  
#>  [9] "isdst"  "zone"   "gmtoff"

# local_bypass
fun <- function() {
  local_bypass()
  names(x)
}
fun()
#>  [1] "sec"    "min"    "hour"   "mday"   "mon"    "year"   "wday"   "yday"  
#>  [9] "isdst"  "zone"   "gmtoff"

# global_bypass (in a package)
.onLoad <- function(libname, pkgname) {
  bypass::global_bypass(asNamespace(pkgname))
}
# then names() will behave like .names() in the whole package

Low level replacement is one of the most useful features.

# without bypass
x <- as.POSIXlt(c("2024-01-01", "2024-01-02"))
cl <- class(x)
x <- unclass(x)
x$year <- c(120L, 121L)
class(x) <- cl
x
#> [1] "2020-01-01 CET" "2021-01-02 CET"

# with bypass
x <- as.POSIXlt(c("2024-01-01", "2024-01-02"))
with_bypass({
  x$year <- c(120L, 121L)
})
x
#> [1] "2020-01-01 CET" "2021-01-02 CET"

In case of replacement of nested elements the difference between both approaches will be even bigger.

Example 2

x <- structure(list(a = 1, b = 2), class = "foo")
c.foo <- function(...) 42
dim.foo <- function(...) 42
`$.foo` <- function(...) 42
length.foo <- function(...) 42
lengths.foo <- function(...) 42
names.foo <- function(...) 42
`[.foo` <- function(...) 42
`[[.foo` <- function(...) 42
unlist.foo <- function(...) 42
  
c(x)
#> [1] 42
.c(x)
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2

dim(x)
#> [1] 42
.dim(x)
#> NULL

x$a
#> [1] 42
.dollar(x, a)
#> [1] 1

lapply(x, identity)
#> $a
#> [1] 42
#> 
#> $b
#> [1] 42
.lapply(x, identity)
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2

sapply(x, identity)
#>  a  b 
#> 42 42
.sapply(x, identity)
#> a b 
#> 1 2

length(x)
#> [1] 42
.length(x)
#> [1] 2

names(x)
#> [1] 42
.names(x)
#> [1] "a" "b"

unlist(x)
#> [1] 42
.unlist(x)
#> a b 
#> 1 2

# NOTE: `local_bypass()` should normally be called in a function so we don't 
# change the global state, here for demo purposes:
local_bypass()
c(x)
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2
dim(x)
#> NULL
x$a
#> [1] 1
lapply(x, identity)
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2
sapply(x, identity)
#> a b 
#> 1 2
length(x)
#> [1] 2
names(x)
#> [1] "a" "b"
unlist(x)
#> a b 
#> 1 2

bypass's People

Contributors

moodymudskipper avatar

Watchers

Christoph Sax avatar  avatar

bypass's Issues

Loading the package throws "incompatible architecture" error

It might be my system settings issue. So, unrelateted to package.

> devtools::load_all(".")
ℹ Loading bypass
ℹ Re-compiling bypass (debug build)
── R CMD INSTALL ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
─  installing *source* package ‘bypass’ ...
   ** using staged installation
   ** libs
   using C compiler: ‘Apple clang version 15.0.0 (clang-1500.1.0.2.5)’
   using SDK: ‘MacOSX14.2.sdk’
   make: Nothing to be done for `all'.
   installing to /private/var/folders/sd/slgy9mrs2494zytqqlydgn7r0000gp/T/RtmpLJGa83/devtools_install_474d315452d2/00LOCK-bypass/00new/bypass/libs
   ** checking absolute paths in shared objects and dynamic libraries
─  DONE (bypass)
Error in dyn.load(dll_copy_file) : 
  unable to load shared object '/var/folders/sd/slgy9mrs2494zytqqlydgn7r0000gp/T//RtmpLJGa83/pkgload474d1b37c1d8/bypass.so':
  dlopen(/var/folders/sd/slgy9mrs2494zytqqlydgn7r0000gp/T//RtmpLJGa83/pkgload474d1b37c1d8/bypass.so, 0x0006): tried: '/var/folders/sd/slgy9mrs2494zytqqlydgn7r0000gp/T//RtmpLJGa83/pkgload474d1b37c1d8/bypass.so' (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64h' or 'x86_64')), '/System/Volumes/Preboot/Cryptexes/OS/var/folders/sd/slgy9mrs2494zytqqlydgn7r0000gp/T//RtmpLJGa83/pkgload474d1b37c1d8/bypass.so' (no such file), '/var/folders/sd/slgy9mrs2494zytqqlydgn7r0000gp/T//RtmpLJGa83/pkgload474d1b37c1d8/bypass.so' (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64h' or 'x86_64')), '/private/var/folders/sd/slgy9mrs2494zytqqlydgn7r0000gp/T/RtmpLJGa83/pkgload474d1b37c1d8/bypass.so' (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64h' or 'x86_64')), '/System/Volumes/Preboot/Cryptexes/

to CRAN

need decent coverage, another check that we don't miss other useful internal generics and close wrappers, and we're ready to go

comparison ops

x <- structure("19469", class = "Date")
x
#> [1] "2023-04-22"
x == ""
#> [1] NA

Created on 2024-06-08 with reprex v2.1.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.