0

I'll keep it simple. Why does this work:

> as.data.frame(c('a', 'b'))
  c("a", "b")
1           a
2           b

But this doesn't:

> as(c('a', 'b'), "data.frame")
Error in as(c("a", "b"), "data.frame") : 
  no method or default for coercing “character” to “data.frame”

I assumed that the latter would simply somehow convert into the former, but I suppose not.

Matthew Saltz
  • 375
  • 4
  • 8
  • 1
    I always associated the plain `as` function with R's S4 object system (although I don't know much S4 having never really used it). So I always just considered it a separate thing from the functions `as.data.frame`, `as.integer`, etc. – joran Oct 09 '15 at 20:54

2 Answers2

3

Maybe the R authors thought replicating the first method would be encouraging bad coding practice. The first result does not look particularly worth emulating because the name of the column will not be easy to use. The data.frame method for character values delivers a much better behaved result since it gets created with a valid name:

> as.data.frame(c('a','b'))
  c("a", "b")
1           a
2           b

data.frame(c('a','b'))
  c..a....b..
1           a
2           b

See what happens when you try to extract values with the name of that column. Since everyone knows that dataframes are really list objects, (right?)... then it would be more natural to expect coders to use a list argument:

data.frame(list(b=c('a', 'b'))  )
  b
1 a
2 b

# same as
> as.data.frame(list(f=c('a','b')))
  f
1 a
2 b

Alex's answer directs you to the as-function code, which elaborates and confirms joran's comment above. That function doesn't use the S3 dispatch, but rather looks up registered coercion methods that have been created by packages or constructed with setAs which is a process that is more commonly used in building S4-methods.

> setAs("character", "data.frame", function(from){ to=as.data.frame.character(from)})
> new=as(c('a', 'b'), "data.frame")
> new
  from
1    a
2    b

The setAs function also allows you to use custom coercion at the time of input with the read.*-functions: How can I completely remove scientific notation for the entire R session

Community
  • 1
  • 1
IRTFM
  • 251,731
  • 20
  • 347
  • 472
  • Thanks for the quick and thorough response. I realize that this isn't the way you would typically create a data.frame, but this response definitely helped with my understanding of `as` and answers the question. So maybe this should be a separate question, but the motivation for this is that I want to create an object to be the same type as another. So basically something like `a – Matthew Saltz Oct 10 '15 at 00:50
  • The only thing needed to make a a vector into a matrix is to use `dim( vec) – IRTFM Oct 10 '15 at 01:53
  • Sorry, I wasn't super clear with that explanation. It's a bit of a funny use case, but I have an object `b`, and some data, and i want to create an object `a` using that data, but I want the resulting class to be the same class as that of `b`. So if `b` is a data.frame, I want `a` to be a data.frame; if `b` is a matrix, I want `a` to be a matrix. I thought that by doing `a – Matthew Saltz Oct 13 '15 at 14:41
  • 1
    Why not: `class(a) – IRTFM Oct 13 '15 at 15:44
1

I believe that it has to do with the fact that as is not a generic function, such as mean:

R> mean
function (x, ...) 
UseMethod("mean")
<bytecode: 0x000000000a617ed0>
<environment: namespace:base>

Since it's not a generic, there is no call to method dispatch (ie UseMethod)

On the other hand, as.data.frame is a generic function-- see methods(class= "data.frame") or the source for as.data.frame

If there was method dispatch on as, your assumption "that the latter would convert to the former" would be correct. Since as is not a generic function, your assumption is wrong.

If you look at the source code to as, you see that it's essentially a call to a number of if-else cases instead of a call to method dispatch. On line 52, you see the catch that returns your error:

if (is.null(asMethod)) 
        stop(gettextf("no method or default for coercing %s to %s", 
                      dQuote(thisClass), dQuote(Class)), domain = NA)

Which gives the return that you see.

Alex W
  • 4,619
  • 4
  • 28
  • 55