-1

I have this function called Dude. it takes Data as a required NanoStringGeoMxSet class, with Norm being "neg" input. I want to through a flag/error for user if class isnt correct. However, Data = (can be any labeled input). I want to allow class to take in this any variable to check class status. Any thoughts?

Dude <- function(Data, Norm) {
  
  if(class(data)[1] != "NanoStringGeoMxSet"){
    stop(paste0("Error: You have the wrong data class, must be NanoStringGeoMxSet" ))
  }

  ## rest of code
}

Dude(Data = data, Norm = "neg")
Genetics
  • 279
  • 2
  • 11
  • 3
    "Any thoughts" on what exactly? What is your question here? Are you having a problem with this current code? If so, can you give any sort of [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input and desired output that can be used to test and verify possible solutions. – MrFlick Jan 12 '23 at 17:40
  • Question is very clear MrFlick. I want to make class() more flexible in dating in variable names that are put into the function. Current code runs fine. But when you change object data to lets say blah. Class will miss this. – Genetics Jan 12 '23 at 17:53
  • 2
    Your question is _not_ clear, Genetics. Why is your current code failing? Are you intentionally re-implementing R's S3 method dispatch? While it has some weaknesses, it is a well-tested mechanism. Perhaps my confusion lies in what *"can be any labeled input"* really means. Please provide sample data that triggers why your `class(data)[1]` trick does not work. (BTW, your conditional should likely be `if (inherits(data, "NanoStringGeoMxSet"))`, this better accounts for the common case where `class(.)` returns a length > 1.) – r2evans Jan 12 '23 at 18:01
  • BTW, your function declaration specifies `Data` but you do `class(data)`, typo? Further, your call uses `Data=data` which, until we're shown otherwise, means the _function_ called `data`. – r2evans Jan 12 '23 at 18:08
  • @ r2evans, no typo. data is called into the function, last line. – Genetics Jan 12 '23 at 18:12
  • You missed my point: `function(Data, Norm)` and then `class(data)` _is a typo_. That is, unless you are intentionally _discarding_ `Data` and are executing scope-breach by assuming that the user has `data` defined in the calling environment. – r2evans Jan 12 '23 at 18:13
  • @r2evans, I am dumb. See what you mean. Should be Data as will pass through into function – Genetics Jan 12 '23 at 18:15

1 Answers1

2

To start the discussion about an S3 implementation, here's a start:

Dude <- function(Data, Norm) UseMethod("Dude")
Dude.NanoStringGeoMxSet <- function(Data, Norm) {
  ## rest of code
}

Dude(mtcars)
# Error in UseMethod("Dude") : 
#   no applicable method for 'Dude' applied to an object of class "data.frame"

If you want to customize the error message, or perhaps recover based on some other criteria, then you can define a "default" method along with the two above:

Dude.default <- function(Data, Norm) {
  stop(paste("unrecognized class:",
       paste(sQuote(class(Data), FALSE), collapse = ", ")))
}

Dude(mtcars)
# Error in Dude.default(mtcars) : unrecognized class: 'data.frame'

FYI, if you want dispatch based on the second (and potentially subsequent) argument as well, you may want to consider R6 instead of S3. Its implementation is a lot more complex than this, but it better implements object-oriented and multi-argument dispatch, and adds public/private members/properties (among other differences). See https://r6.r-lib.org if you're at all interested.

r2evans
  • 141,215
  • 6
  • 77
  • 149