12  Tipos básicos

12.1 Introducción

Para hablar de objetos y programación orientada a objetos en R, primero debemos aclarar una confusión fundamental sobre dos usos de la palabra “objeto”. Hasta ahora en este libro, hemos usado la palabra en el sentido general captado por la concisa cita de John Chambers: “Todo lo que existe en R es un objeto”. Sin embargo, aunque todo es un objeto, no todo está orientado a objetos. Esta confusión surge porque los objetos base provienen de S y se desarrollaron antes de que nadie pensara que S podría necesitar un sistema OOP. Las herramientas y la nomenclatura evolucionaron orgánicamente durante muchos años sin un solo principio rector.

La mayoría de las veces, la distinción entre objetos y objetos orientados a objetos no es importante. Pero aquí tenemos que entrar en detalles esenciales, así que usaremos los términos objetos base y objetos OO para distinguirlos.

Estructura

  • La Sección 12.2 le muestra cómo identificar objetos base y OO.

  • La Sección 12.3 proporciona un conjunto completo de los tipos base utilizados para construir todos los objetos.

12.2 Base versus objetos OO

Para saber la diferencia entre un objeto base y OO, usa is.object() o sloop::otype():

# Un objeto básico:
is.object(1:10)
#> [1] FALSE
sloop::otype(1:10)
#> [1] "base"

# Un objeto OO
is.object(mtcars)
#> [1] TRUE
sloop::otype(mtcars)
#> [1] "S3"

Técnicamente, la diferencia entre los objetos base y OO es que los objetos OO tienen un atributo de “clase”:

attr(1:10, "class")
#> NULL

attr(mtcars, "class")
#> [1] "data.frame"

Puede que ya estés familiarizado con la función class(). Es seguro aplicar esta función a objetos S3 y S4, pero devuelve resultados engañosos cuando se aplica a objetos base. Es más seguro usar sloop::s3_class(), que devuelve la clase implícita que los sistemas S3 y S4 usarán para seleccionar métodos. Aprenderá más sobre s3_class() en la Sección 13.7.1.

x <- matrix(1:4, nrow = 2)
class(x)
#> [1] "matrix" "array"
sloop::s3_class(x)
#> [1] "matrix"  "integer" "numeric"

12.3 Tipos básicos

Mientras que solo los objetos OO tienen un atributo de clase, cada objeto tiene un tipo base:

typeof(1:10)
#> [1] "integer"

typeof(mtcars)
#> [1] "list"

Los tipos base no forman un sistema OOP porque las funciones que se comportan de manera diferente para diferentes tipos base se escriben principalmente en código C que usa instrucciones de cambio. Esto significa que solo R-core puede crear nuevos tipos, y crear un nuevo tipo es mucho trabajo porque cada declaración de cambio debe modificarse para manejar un nuevo caso. Como consecuencia, rara vez se agregan nuevos tipos base. El cambio más reciente, en 2011, agregó dos tipos exóticos que nunca se ven en R, pero que son necesarios para diagnosticar problemas de memoria. Antes de eso, el último tipo agregado fue un tipo base especial para objetos S4 agregado en 2005.

En total, hay 25 tipos de base diferentes. Se enumeran a continuación, agrupados libremente según el lugar en el que se analicen en este libro. Estos tipos son los más importantes en el código C, por lo que a menudo los verá llamados por sus nombres de tipo C. Los he incluido entre paréntesis.

  • Vectores, Capítulo 3, incluye tipos NULL (NILSXP), logical (LGLSXP), integer (INTSXP), double (REALSXP), complex (CPLXSXP), character (STRSXP), list (VECSXP), y raw (RAWSXP).

    typeof(NULL)
    #> [1] "NULL"
    typeof(1L)
    #> [1] "integer"
    typeof(1i)
    #> [1] "complex"
  • Las funciones, Capítulo 6, incluyen los tipos cierre (funciones regulares de R, CLOSXP), especiales (funciones internas, SPECIALSXP) e incorporadas (funciones primitivas, BUILTINSXP).

    typeof(mean)
    #> [1] "closure"
    typeof(`[`)
    #> [1] "special"
    typeof(sum)    
    #> [1] "builtin"

    Las funciones internas y primitivas se describen en la Sección 6.2.2.

  • Entornos, Capítulo 7, tienen tipo entorno (ENVSXP).

    typeof(globalenv())
    #> [1] "environment"
  • El tipo S4 (S4SXP), Capítulo 15, se usa para las clases de S4 que no heredan de un tipo base existente.

    mle_obj <- stats4::mle(function(x = 1) (x - 2) ^ 2)
    typeof(mle_obj)
    #> [1] "S4"
  • Los componentes del lenguaje, Capítulo 18), incluyen símbolo (también conocido como nombre, SYMSXP), idioma (generalmente llamadas llamadas, LANGSXP) y pairlist (usado para argumentos de función, LISTSXP ) tipos.

    typeof(quote(a))
    #> [1] "symbol"
    typeof(quote(a + 1))
    #> [1] "language"
    typeof(formals(mean))
    #> [1] "pairlist"

    expression (EXPRSXP) es un tipo de propósito especial que solo es devuelto por parse() y expression(). Las expresiones generalmente no son necesarias en el código de usuario.

  • Los tipos restantes son esotéricos y rara vez se ven en R. Son importantes principalmente para el código C: externalptr (EXTPTRSXP), weakref (WEAKREFSXP), bytecode (BCODESXP), promise (PROMSXP), ... (DOTSXP), y any (ANYSXP).

Es posible que hayas oído hablar de mode() y storage.mode(). No utilice estas funciones: solo existen para proporcionar nombres de tipo que sean compatibles con S.

12.3.1 Tipo numérico

Tenga cuidado al hablar del tipo numérico, porque R usa “numérico” para referirse a tres cosas ligeramente diferentes:

  1. En algunos lugares, numérico se usa como un alias para el tipo doble. Por ejemplo, as.numeric() es idéntico a as.double(), y numeric() es idéntico a double().

    (R también usa ocasionalmente real en lugar de doble; NA_real_ es el único lugar donde es probable que encuentres esto en la práctica.)

  2. En los sistemas S3 y S4, numérico se usa como una forma abreviada de tipo entero o doble, y se usa cuando se seleccionan métodos:

    sloop::s3_class(1)
    #> [1] "double"  "numeric"
    sloop::s3_class(1L)
    #> [1] "integer" "numeric"
  3. is.numeric() pruebas para objetos que se comportan como números. Por ejemplo, los factores tienen el tipo “entero” pero no se comportan como números (es decir, no tiene sentido tomar la media del factor).

    typeof(factor("x"))
    #> [1] "integer"
    is.numeric(factor("x"))
    #> [1] FALSE

En este libro, siempre uso numérico para indicar un objeto de tipo entero o doble.