Learn R Programming

constructive

{constructive} prints code that can be used to recreate R objects. In a sense it is similar to base::dput() or base::deparse() but {constructive} strives to use idiomatic constructors (factor for factors, as.Date() for dates, data.frame() for data frames etc), in order to get output readable by humans.

Some use cases are:

  • Snapshot tests
  • Exploring objects (alternative to dput() or str())
  • Creating reproducible examples from existing data
  • Comparing two objects (using construct_diff())

Installation

Install the last stable version from CRAN:

install.packages('constructive')

Or install the development version from cynkra R-universe:

install.packages('constructive', repos = c('https://cynkra.r-universe.dev', 'https://cloud.r-project.org'))

Or directly from github:

pak::pak("cynkra/constructive")

Comparison with dput()

A few examples compared to their dput() output.

library(constructive)

construct(head(iris, 2))
#> data.frame(
#>   Sepal.Length = c(5.1, 4.9),
#>   Sepal.Width = c(3.5, 3),
#>   Petal.Length = c(1.4, 1.4),
#>   Petal.Width = c(0.2, 0.2),
#>   Species = factor(c("setosa", "setosa"), levels = c("setosa", "versicolor", "virginica"))
#> )

dput(head(iris, 2))
#> structure(list(Sepal.Length = c(5.1, 4.9), Sepal.Width = c(3.5, 
#> 3), Petal.Length = c(1.4, 1.4), Petal.Width = c(0.2, 0.2), Species = structure(c(1L, 
#> 1L), levels = c("setosa", "versicolor", "virginica"), class = "factor")), row.names = 1:2, class = "data.frame")

construct(.leap.seconds)
#> as.POSIXct(
#>   c(
#>     "1972-07-01", "1973-01-01", "1974-01-01", "1975-01-01", "1976-01-01",
#>     "1977-01-01", "1978-01-01", "1979-01-01", "1980-01-01", "1981-07-01",
#>     "1982-07-01", "1983-07-01", "1985-07-01", "1988-01-01", "1990-01-01",
#>     "1991-01-01", "1992-07-01", "1993-07-01", "1994-07-01", "1996-01-01",
#>     "1997-07-01", "1999-01-01", "2006-01-01", "2009-01-01", "2012-07-01",
#>     "2015-07-01", "2017-01-01"
#>   ),
#>   tz = "GMT"
#> )

dput(.leap.seconds)
#> structure(c(78796800, 94694400, 126230400, 157766400, 189302400, 
#> 220924800, 252460800, 283996800, 315532800, 362793600, 394329600, 
#> 425865600, 489024000, 567993600, 631152000, 662688000, 709948800, 
#> 741484800, 773020800, 820454400, 867715200, 915148800, 1136073600, 
#> 1230768000, 1341100800, 1435708800, 1483228800), class = c("POSIXct", 
#> "POSIXt"), tzone = "GMT")

library(dplyr, warn.conflicts = FALSE)
grouped_band_members <- group_by(band_members, band)

dput(grouped_band_members)
#> structure(list(name = c("Mick", "John", "Paul"), band = c("Stones", 
#> "Beatles", "Beatles")), class = c("grouped_df", "tbl_df", "tbl", 
#> "data.frame"), row.names = c(NA, -3L), groups = structure(list(
#>     band = c("Beatles", "Stones"), .rows = structure(list(2:3, 
#>         1L), ptype = integer(0), class = c("vctrs_list_of", "vctrs_vctr", 
#>     "list"))), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
#> -2L), .drop = TRUE))

construct(grouped_band_members)
#> tibble::tibble(name = c("Mick", "John", "Paul"), band = c("Stones", "Beatles", "Beatles")) |>
#>   dplyr::group_by(band)

We can provide to the data argument a named list, an environment, a package where to look for data, or an unnamed list of such items, so we don’t print more than necessary, for instance improving the previous example:

construct(grouped_band_members, data = "dplyr")
#> band_members |>
#>   dplyr::group_by(band)

Customize the output using constructive options

Some objects can be constructed in several ways, for instance a tibble might be constructed using tibble::tibble() or using tibble::tribble().

The opts_*() family of functions provides ways to tweak the output code, namely setting the constructor itself or options used by the constructor

construct(band_members, opts_tbl_df("tribble"))
#> tibble::tribble(
#>   ~name,  ~band,
#>   "Mick", "Stones",
#>   "John", "Beatles",
#>   "Paul", "Beatles",
#> )
construct(band_members, opts_tbl_df("tribble", justify = "right"))
#> tibble::tribble(
#>    ~name,     ~band,
#>   "Mick",  "Stones",
#>   "John", "Beatles",
#>   "Paul", "Beatles",
#> )

r <- as.raw(c(0x68, 0x65, 0x6c, 0x6c, 0x6f))
construct(r)
#> as.raw(c(0x68, 0x65, 0x6c, 0x6c, 0x6f))
construct(r, opts_raw(representation = "decimal"))
#> as.raw(c(104, 101, 108, 108, 111))
construct(r, opts_raw("charToRaw"))
#> charToRaw("hello")

These functions have their own documentation page and are referenced in ?construct.

For every class that doesn’t refer to an internal type a “next” constructor is available, so we can conveniently explore objects using lower level constructors.

construct(band_members, opts_tbl_df("next"))
#> data.frame(name = c("Mick", "John", "Paul"), band = c("Stones", "Beatles", "Beatles")) |>
#>   structure(class = c("tbl_df", "tbl", "data.frame"))

construct(band_members, opts_tbl_df("next"), opts_data.frame("next"))
#> list(name = c("Mick", "John", "Paul"), band = c("Stones", "Beatles", "Beatles")) |>
#>   structure(class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -3L))

Other functions

  • construct_multi() constructs several objects from a named list or an environment
  • construct_reprex() wraps construct_multi() and constructs all the objects of the local environment, or from the caller environments.
  • construct_dput() constructs the objects using only low level constructors, like structure(), list(), c(), very similarly to base::dput()
  • construct_base() constructs the objects using only base R functions.
  • construct_clip() writes to the clipboard, see also ?constructive-global_options
  • construct_diff() highlights the differences in the code used to produce 2 objects, it’s an alternative to waldo::compare().
  • construct_dump() is similar to base::dump(), it’s a wrapper around construct_multi() that writes to a file.
  • construct_signature() constructs a function signature such as the one we see in the “usage” section of a function’s help file. outputs the code produced
  • construct_issues() is used without arguments to check what were the issues encountered with the last reconstructed object, it can also be provided a specific constructive object.
  • deparse_call() is an alternative to base::deparse() and rlang::expr_deparse() that handles additional corner cases and fails when encountering tokens other than symbols and syntactic literals .

Note about environments and external pointers

Environments use reference semantics, they cannot be copied. An attempt to copy an environment would indeed yield a different environment and identical(env, copy) would be FALSE (read more about it in ?opts_environment).

In some case we can build code that points to a specific environment, for instance:

construct(globalenv())
#> .GlobalEnv
construct(environment(setNames))
#> asNamespace("stats")

When it’s not possible we use constructive::.env() function for this purpose.

e1 <- new.env(parent = .GlobalEnv)
e1$x <- 1
construct(e1)
#> constructive::.env("0x131515348", parents = "global")

constructive::.env() fetches the environment from its memory address. The parents argument doesn’t do anything, it provides as additional information the sequence of parents until we reach a special environment.

This strategy is convenient because it always works, but it’s not reproducible between sessions as the memory address is not stable. Moreover it doesn’t tell us anything about the environment’s content.

Depending on what compromise you’re ready to make, you might use different constructions in opts_environment(). For the case above, choosing "list2env" works well :

construct(e1, opts_environment("list2env"))
#> list2env(list(x = 1), parent = .GlobalEnv)

constructive::.xptr() is the counterpart of constructive::.env() to construct "externalptr" objects from a memory address.

Extending constructive

You can define your own constructors and methods!

For more information see vignette("User-defined-methods-and-constructors", package = "constructive")

Copy Link

Version

Install

install.packages('constructive')

Monthly Downloads

2,472

Version

1.3.0

License

MIT + file LICENSE

Issues

Pull Requests

Stars

Forks

Maintainer

Antoine Fabri

Last Published

September 19th, 2025

Functions in constructive (1.3.0)

constructive-package

constructive: Display Idiomatic Code to Construct Most R Objects
.cstr_pipe

Insert a pipe between two calls
.cstr_construct

Generic for object code generation
.cstr_wrap

Wrap argument code in function call
.cstr_repair_attributes

Repair attributes after idiomatic construction
.cstr_options

Create constructive options
deparse_call

Deparse a language object
.env

Fetch environment from memory address
.cstr_combine_errors

Combine errors
.cstr_apply

.cstr_apply
.xptr

Build a pointer from a memory address
opts_CoordTransform

Constructive options for class 'CoordTransform'
extend-constructive

Extend constructive
opts_AsIs

Constructive options for the class AsIs
opts_GuideAxisStack

Constructive options for class 'GuideAxisStack'
opts_GuideAxis

Constructive options for class 'GuideAxis'
opts_Date

Constructive options class 'Date'
opts_CoordRadial

Constructive options for class 'CoordRadial'
opts_GuideAxisLogticks

Constructive options for class 'GuideAxisLogticks'
opts_FacetNull

Constructive options for class 'FacetNull'
opts_GuideNone

Constructive options for class 'GuideNone'
opts_Guides

Constructive options for class 'Guides'
opts_GuideColourbar

Constructive options for class 'GuideColourbar'
opts_GuideColoursteps

Constructive options for class 'GuideColoursteps'
opts_POSIXct

Constructive options for class 'POSIXct'
opts_Layer

Constructive options for class 'Layer' (ggplot2)
opts_GuideLegend

Constructive options for class 'GuideLegend'
opts_GuideCustom

Constructive options for class 'GuideCustom'
opts_GuideAxisTheta

Constructive options for class 'GuideAxisTheta'
opts_GuideBins

Constructive options for class 'GuideBins'
opts_S7_external_generic

Constructive options for class 'S7_external_generic'
opts_S7_class

Constructive options for class 'S7_class'
opts_S7_base_class

Constructive options for class 'S7_base_class'
opts_S7_any

Constructive options for class 'S7_any'
opts_R6ClassGenerator

Constructive options for class 'R6ClassGenerator'
opts_R_system_version

Constructive options for R_system_version
opts_POSIXlt

Constructive options for class 'POSIXlt'
opts_R6

Constructive options for class 'R6'
opts_S4

Constructive options for class 'S4'
opts_S7_S3_class

Constructive options for class 'S7_S3_class'
opts_classGeneratorFunction

Constructive options for class 'classGeneratorFunction'
opts_S7_property

Constructive options for class 'S7_property'
opts_S7_generic

Constructive options for class 'S7_generic'
opts_character

Constructive options for type 'character'
opts_atomic

Constructive options for atomic types
opts_classPrototypeDef

Constructive options for class 'classPrototypeDef'
opts_blob

Constructive options for class 'blob'
opts_array

Constructive options for arrays
opts_S7_object

Constructive options for class 'S7_object'
opts_S7_union

Constructive options for class 'S7_union'
opts_dots

Constructive options for type '...'
opts_classRepresentation

Constructive options for class 'classRepresentation'
opts_double

Constructive options for type 'double'
opts_constructive_options

Constructive options for the class constructive_options
opts_data.frame

Constructive options for class 'data.frame'
opts_data.table

Constructive options for class 'data.table'
opts_ellmer_TypeBasic

Constructive options for class 'ellmer::TypeBasic`'
opts_ellmer_TypeArray

Constructive options for class 'ellmer::TypeArray`'
opts_complex

Constructive options for type 'complex'
opts_dm

Constructive options class 'dm'
opts_factor

Constructive options for class 'factor'
opts_formula

Constructive options for formulas
opts_ggplot

Constructive options for class 'ggplot'
opts_environment

Constructive options for type 'environment'
opts_ellmer_TypeEnum

Constructive options for class 'ellmer::TypeEnum`'
opts_ellmer_TypeJsonSchema

Constructive options for class 'ellmer::TypeJsonSchema`'
opts_externalptr

Constructive options for type 'externalptr'
opts_function

Constructive options for functions
opts_ggplot2_ggplot

Constructive options for class 'ggplot2::ggplot'
opts_ellmer_TypeObject

Constructive options for class 'ellmer::TypeObject`'
opts_integer

Constructive options for type 'integer'
opts_matrix

Constructive options for matrices
opts_mts

Constructive options for time-series objets
opts_logical

Constructive options for type 'logical'
opts_grouped_df

Constructive options for class 'grouped_df'
opts_hexmode

Constructive options for class 'hexmode'
opts_ggplot2_labels

Constructive options for class 'ggplot2::labels'
opts_language

Constructive options for type 'language'
opts_integer64

Constructive options for class 'integer64'
opts_list

Constructive options for type 'list'
opts_rowwise_df

Constructive options for class 'rowwise_df'
opts_package_version

Constructive options for package_version
opts_pairlist

Constructive options for pairlists
opts_object

Constructive options for class 'object'
opts_quosures

Constructive options for class 'quosures'
opts_raw

Constructive options for type 'raw'
opts_numeric_version

Constructive options for numeric_version
opts_quosure

Constructive options for class 'quosure'
opts_octmode

Constructive options for class 'octmode'
opts_ordered

Constructive options for class 'ordered'
opts_xts

Constructive options for class 'xts'
opts_yearqtr

Constructive options for class 'yearqtr'
opts_yearmon

Constructive options for class 'yearmon'
opts_xml_document

Constructive options for class 'xml_document'
opts_weakref

Constructive options for the class weakref
opts_vctrs_list_of

Constructive options for class 'data.table'
opts_tbl_df

Constructive options for tibbles
opts_zoo

Constructive options for class 'zoo'
opts_ts

Constructive options for time-series objets
opts_zooreg

Constructive options for class 'zooreg'
templates

Extend constructive
other-opts

Other Opts Functions
print.constructive_code

Print code with syntax highlighting
construct_reprex

construct_reprex
construct_dput

Construct using only low level constructors
construct_clip

Construct to clipboard
construct_diff

Display diff of object definitions
construct_dump

Dump Constructed Code to a File
construct_issues

Show constructive issues
construct

Build code to recreate an object
constructive-global_options

Global Options
compare_options

Options for waldo::compare
construct_signature

Construct a function's signature