Hello @RussellPierce! Apologies for the delayed response here. This is a great question!!
The reason for this is that dimnames uses S3 dispatch! You can see this with the following:
dimnames.data.frame
#> function (x)
#> list(row.names(x), names(x))
#> <bytecode: 0x7f814ab3cfc0>
#> <environment: namespace:base>
dbplyr:::dimnames.tbl_lazy
#> function (x)
#> {
#> list(NULL, op_vars(x$ops))
#> }
#> <environment: namespace:dbplyr>
Created on 2020-03-20 by the reprex package (v0.3.0)
I don't know a whole lot of the specifics about how this works in base R, but perhaps others will! Unfortunately this thread is closed already
So perhaps a new discussion / thread on how base R primitives do S3 dispatch / how to discern that would be worthwhile? 