[R-pkg-devel] tryCatch defensive programming guidance
Martin Maechler
maechler at stat.math.ethz.ch
Wed Mar 1 22:01:16 CET 2017
>>>>> Berry Boessenkool <berryboessenkool at hotmail.com>
>>>>> on Wed, 1 Mar 2017 14:52:10 +0000 writes:
> Hi Glenn,
> Better late than never:
> couldn't you simply use try?
> result <- try( log("a") )
> The printing is horrible: people will think an error
> occured (but the function didn't stop!)
> I tend to use it like this (which may be totally
> unintended):
> res <- try(log("a"), silent=TRUE)
> if(inherits(res, "try-error"))
> {
> message("log failed: ",res,". Now continuing with res=0.")
> res <- 0
> }
but if you ever looked: try() is just a wrapper to tryCatch()
and using try(*, silent=TRUE) is even closer to a pretty simple tryCatch(.)
Historically, tryCatch() did not exist, but try() did.
So much of "old code" still has try() calls in it.
I consider try() as convenience function for interactive use but
would always use tryCatch() for new code in my packages.
> See here for my version that captures errors/warnings/messages with call tracing:
> https://www.rdocumentation.org/packages/berryFunctions/topics/tryStack
I'd recommend you switch to tryCatch(): It is more flexible and
more directly "configurable" than try() -- which also got some historical
flexibility by the "hack" (not functional programming)
of depending on getOption("show.error.messages") in the
default case silent = FALSE {needed to suppress other
packages' using try(.) 's printing of error messages as if
*error*s inspite of the fact that they were caught.
.... and back to the OP:
I think that's your only small problem that you chose
error = function(e) print(e)
because that prints "as if" you had an error.
Martin
> Regards,
> Berry
> ________________________________
> From: R-package-devel <r-package-devel-bounces at r-project.org> on behalf of Glenn Schultz <glennmschultz at me.com>
> Sent: Saturday, February 25, 2017 15:50
> To: R Package Development
> Subject: [R-pkg-devel] tryCatch defensive programming guidance
> All,
> I have the following to create a class PriceTypes. I use try catch on the function and it gives me the error
> price <- tryCatch(PriceTypes(price = "100")
> ,error = function(e) print(e)
> ,warning = function(w) print(w))
> <simpleError in PriceTypes(price = "100"): tail value is missing>
>>
> I read the section on tryCatch and withCallingHandlers as well the manual but I am still not clear as to how to use tryCatch in the function below I tried
> PriceTypes <- TryCatch(
> function(){}
> ), function(e) print(error)
> but this is obviously wrong as it did not work. My question can I use tryCatch in the function itself or only when I invoke the function.
> Best Regards,
> Glenn
> #' An S4 class representating bond price
> #'
> #' This class is used to create and pass the price types reported to
> #' investors and used in analytics. For example price is often reported as
> #' decimal or fractions 32nds to investors but price basis (price/100) is
> #' used to calculate proceeds and compute metrics like yield, duration, and
> #' partial durations.
> #' @slot PriceDecimal A numeric value the price using decimal notation
> #' @slot Price32nds A character the price using 32nds notation
> #' @slot PriceBasis A numeric value price decimal notation in units of 100
> #' @slot PriceDecimalString A character the price using decimal notation
> #' @exportClass PriceTypes
> setClass("PriceTypes",
> representation(
> PriceDecimal = "numeric",
> Price32nds = "character",
> PriceBasis = "numeric",
> PriceDecimalString = "character")
> )
> setGeneric("PriceTypes", function(price = numeric())
> {standardGeneric("PriceTypes")})
> #' A standard generic function get the slot PriceDecimal
> #'
> #' @param object an S4 object
> #' @export PriceDecimal
> setGeneric("PriceDecimal", function(object)
> {standardGeneric("PriceDecimal")})
> #' A standard generic function to set the slot PriceDecimal
> #'
> #' @param object an S4 object
> #' @param value the replacement value of the slot
> #' @export PriceDecimal<-
> setGeneric("PriceDecimal<-", function(object, value)
> {standardGeneric("PriceDecimal<-")})
> #' A standard generic function to get the slot Price32nds
> #'
> #' @param object an S4 object
> #' @export Price32nds
> setGeneric("Price32nds", function(object)
> {standardGeneric("Price32nds")})
> #' A standard generic function to set the slot Price32nds
> #'
> #' @param object an S4 object
> #' @param value the replacement value of the slot
> #' @export Price32nds<-
> setGeneric("Price32nds<-", function(object, value)
> {setGeneric("Price32nds")})
> #' A standard generic to get the slot PriceBasis
> #'
> #' @param object an S4 object
> #' @export PriceBasis
> setGeneric("PriceBasis", function(object)
> {standardGeneric("PriceBasis")})
> #' A standard generic to set the slot PriceBasis
> #'
> #' @param object A S4 object of type PriceTypes
> #' @param value the replacement value of the slot
> #' @export PriceBasis<-
> setGeneric("PriceBasis<-", function(object, value)
> {standardGeneric("PriceBasis<-")})
> #' A standard generic to get the slot PriceDecimalString
> #'
> #' @param object A S4 object of the type PriceTypes
> #' @export
> setGeneric("PriceDecimalString", function(object)
> {setGeneric("PriceDecimalString")})
> #' A standard generic to set the slot PriceDecimalString
> #'
> #' @param object A S4 object of the type PriceTypes
> #' @param value The replacement value of the slot
> #' @export
> setGeneric("PriceDecimalString<-", function(object, value)
> {setGeneric("PriceDecimalString<-")})
> setMethod("initialize",
> signature("PriceTypes"),
> function(.Object,
> PriceDecimal = numeric(),
> Price32nds = "character",
> PriceBasis = numeric(),
> PriceDecimalString = "character",
> ...){
> callNextMethod(.Object,
> PriceDecimal = PriceDecimal,
> Price32nds = Price32nds,
> PriceBasis = PriceBasis,
> PriceDecimalString = PriceDecimalString,
> ...)
> })
> #' A method to extract PriceDecimal from slot of class PriceTypes
> #'
> #' @param object an S4 object of the type PriceTypes
> #' @exportMethod PriceDecimal
> setMethod("PriceDecimal", signature("PriceTypes"),
> function(object){object at PriceDecimal})
> #' A method to set PriceDecimal in slot of class PriceTypes
> #'
> #' @param object an S4 object of the typre PriceTypes
> #' @param value the replacement value of the slot
> #' @exportMethod PriceDecimal<-
> setReplaceMethod("PriceDecimal", signature("PriceTypes"),
> function(object, value){
> object at PriceDecimal <- value
> return(object)
> })
> #' A method to extract Price32nds from slot of class PriceTypes
> #'
> #' @param object an S4 object of the type PriceTypes
> #' @exportMethod Price32nds
> setMethod("Price32nds", signature("PriceTypes"),
> function(object){object at Price32nds})
> #' A method to set Price32nds in slot of class PriceTypes
> #'
> #' @param object an S4 object of the type PriceTypes
> #' @param value the replacement value of the slot
> setReplaceMethod("Price32nds", signature("PriceTypes"),
> function(object, value){
> object at Price32nds <- value
> return(object)
> })
> #' A method to extract PriceBasis from slot of class PriceTypres
> #'
> #' @param object an S4 object of the type PriceType
> #' @exportMethod PriceBasis
> setMethod("PriceBasis", signature("PriceTypes"),
> function(object){object at PriceBasis})
> #' a method to set PriceBasis from slot of class PriceTypes
> #'
> #' @param object an S4 object of the type PriceTypes
> #' @param value the replacement value of the slot
> #' @exportMethod PriceBasis<-
> setReplaceMethod("PriceBasis", signature("PriceTypes"),
> function(object, value){
> object at PriceBasis <- value
> return(object)
> })
> #' A method to extract PriceDecimalString from slot of class PriceTypes
> #'
> #' @param object an S4 object of type PriceTypes
> #' @exportMethod PriceDecimalString
> setMethod("PriceDecimalString", signature("PriceTypes"),
> function(object){object at PriceDecimalString})
> #' A method to set PriceDecimalString from slot of class PriceTypes
> #'
> #' @param object an S4 object of type PriceTypes
> #' @param value the replacement value of the slot
> #' @exportMethod PriceDecimalString<-
> setReplaceMethod("PriceDecimalString", signature("PriceTypes"),
> function(object, value){
> object at PriceDecimalString <- value
> return(object)})
> #' PriceTypes is a constructor function for the class PriceTypes
> #'
> #' @param price character the price in either
> #' decimal notation (example "100.125") or 32nds notation (example "100-4")
> #' @export PriceTypes
> PriceTypes <- function(price){
> PriceBasis = 100
> Units = 32
> if(mode(price) != "character") stop ("price must be a character")
> if(is.na(strsplit(price, "\\.|\\-")[[1]][2]) == TRUE) stop (
> "tail value is missing")
> Convertto32nds <- function(Price = "character"){
> #convert price to numeric value
> Price = as.numeric(Price)
> tail32nds = round(x = (Price - floor(x = Price)) * 32, digits = 4)
> Price = paste(as.character(floor(x=Price)),
> "-",
> as.character(tail32nds),
> sep = "")
> return(Price)
> }
> ConverttoDecimal <- function(Price = "character", Units = numeric()){
> SplitPrice = strsplit(as.character(Price), "-")
> handle = as.numeric(SplitPrice[[1]][1])
> TailDecimal = signif(as.numeric(SplitPrice[[1]][2])/Units,8)
> TailDecimal = gsub("(^|[^0-9])0+", "\\1", TailDecimal, perl = TRUE)
> Price = paste(as.character(handle),
> as.character(TailDecimal),sep="")
> return(Price)
> }
> ConverttoString <- function(PriceDecimal = numeric()){
> sprintf("%.8f", PriceDecimal)
> }
> # Convert Price when entered as a decimal value
> if(grepl(".", as.character(price), fixed = TRUE) == TRUE){
> Price_Decimal = format(as.numeric(price), nsmall =2)
> Price_32nds = Convertto32nds(Price = price)
> Price_Basis = as.numeric(price) / PriceBasis
> Price_Decimal_String = ConverttoString(
> PriceDecimal = as.numeric(Price_Decimal))
> }
> if(grepl("-", as.character(price), fixed = TRUE) == TRUE){
> Price_Decimal = ConverttoDecimal(Price = price, Units = Units)
> Price_32nds = price
> Price_Basis = as.numeric(Price_Decimal)/PriceBasis
> Price_Decimal_String = ConverttoString(
> PriceDecimal = as.numeric(Price_Decimal))
> }
> new("PriceTypes",
> PriceDecimal = as.numeric(Price_Decimal),
> Price32nds = Price_32nds,
> PriceBasis = as.numeric(Price_Basis),
> PriceDecimalString = Price_Decimal_String
> )
> }
More information about the R-package-devel
mailing list