rstudio / shiny

Easy interactive web applications with R
https://shiny.posit.co/
Other
5.36k stars 1.87k forks source link

Inconsistent return types from numericInput #3738

Open daattali opened 1 year ago

daattali commented 1 year ago

The return type from numericInput should be "numeric". However, it seems like it's either an integer or a numeric, depending on what number is chosen. In my opinion it's bad practice to return different types -- the user should know what to expect always. I just ran into an issue where I was expecting objects of numeric class and it took me a while to realize that both integer and numeric are being returned.

You can use the following example app to see this, set the number to 5.0 and then to 5.1:

library(shiny)

ui <- fluidPage(
  numericInput("num", "num", 5)
)

server <- function(input, output, session) {
  observe({
    str(input$num)
  })
}

shinyApp(ui, server)
cpsievert commented 1 year ago

I think an argument could be made that this is actually "expected" behavior, especially given that this is how {jsonlite} behaves:

> str(jsonlite::fromJSON("[1.1]"))
 num 1.1
> str(jsonlite::fromJSON("[1]"))
 int 1

I'd be curious to hear though why you're using inherits(x, "numeric") instead of is.numeric(x)?

daattali commented 1 year ago

Another potential problem is that an invalid number returns NA (which is of type logical) instead of NA_real_ which is type numeric.

In my specific case right now, I'm using inherits() because it's a more general check. As an oversimplication: I'm building a typed list where you have to announce the type ahead of time. The type is the class of the objects that will be accepted. If I want to create a list of "numeric" objects, then I only want to accept that. It would have been useful if in R integers inherited from numerics but that's not the case. Something is either numeric or integer. This isn't shiny related at all.

I was creating a small shiny app as a demo and I figured I could use a numeric input to supply numeric objects. Then I discovered that numeric input doesn't necessarily return numerics. Of course I can forcibly cast the returned value with as.numeric(), that's easy, but that's a workaround. I do strongly believe that a numericInput should exclusively return numerics, it's what would be expected, and follows the principle of a function always returning the same "type".

I understand that this may result from the json conversion, but I wouldn't agree that this is expected behaviour. In JSON's case, doing this makes sense, because the JSON parsing has no context of what the user is expecting. But numericInput does give the assumption that it's for numerics.