From 0b4c1a763ad094858845b3daa003f5af40194b59 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Tue, 16 Jul 2024 10:00:23 +0000 Subject: [PATCH] build based on dc66f8c --- dev/index.html | 12 ++++++------ dev/search/index.html | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dev/index.html b/dev/index.html index f27814d..cde7034 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,6 +1,6 @@ Home · ConstructionBase.jl

ConstructionBase.jl

ConstructionBase allows flexible construction and destructuring of objects. There are two levels of under which this can be done:

The raw level

This is where Base.fieldnames, Base.getfield, Base.setfield! live. This level is what an object is ultimately composed of including all private details. At the raw level ConstructionBase adds constructorof and getfields.

The semantic level

This is where Base.propertynames, Base.getproperty and Base.setproperty! live. This level is typically the public interface of a type, it may hide private details and do magic tricks. At the semantic level ConstructionBase adds setproperties and getproperties.

Interface

ConstructionBase.constructorofFunction
constructorof(T::Type) -> constructor

Return an object constructor that can be used to construct objects of type T from their field values. Typically constructor will be the type T with all parameters removed:

julia> using ConstructionBase
 
 julia> struct T{A,B}
            a::A
@@ -37,7 +37,7 @@
 T{Float64, Int64}(1.0, 2)
 
 julia> constructorof(typeof(t))(10, 2)
-T{Int64, Int64}(10, 2)

constructorof belongs to the raw level. constructorof is generated for all anonymous Functions lacking constructors, identified as having gensym # in their names. A custom struct <: Function with a gensym name may need to define constructorof manually.

See also Tips section in the manual

source
ConstructionBase.getfieldsFunction
getfields(obj) -> NamedTuple
+T{Int64, Int64}(10, 2)

constructorof belongs to the raw level. constructorof is generated for all anonymous Functions lacking constructors, identified as having gensym # in their names. A custom struct <: Function with a gensym name may need to define constructorof manually.

See also Tips section in the manual

source
ConstructionBase.getfieldsFunction
getfields(obj) -> NamedTuple
 getfields(obj::Tuple) -> Tuple

Return a NamedTuple containing the fields of obj. On Tuples getfields is the identity function instead, since Tuple fields have no symbolic names.

Examples

julia> using ConstructionBase
 
 julia> struct S{A,B}
@@ -58,7 +58,7 @@
 end

However the actual implementation can be more optimized. For builtin types, there can also be deviations from this semantics:

  • getfields(::Tuple)::Tuple since Tuples don't have symbolic fieldnames
  • There are some types in Base that have undef fields. Since accessing these results in an error, getfields instead just omits these.

Implementation

The semantics of getfields should not be changed for user defined types. It should return the raw fields as a NamedTuple in the struct order. In other words it should be equivalent to

function getfields(obj::T) where {T}
     fnames = fieldnames(T)
     NamedTuple{fnames}(getfield.(Ref(obj), fnames))
-end

even if that includes private fields of obj. If a change of semantics is desired, consider overloading getproperties instead. See also getproperties, constructorof

source
ConstructionBase.getpropertiesFunction
getproperties(obj)::NamedTuple
 getproperties(obj::Tuple)::Tuple

Return the properties of obj as a NamedTuple. Since Tuple don't have symbolic properties, getproperties is the identity function on tuples.

Examples

julia> using ConstructionBase
 
 julia> struct S
@@ -74,7 +74,7 @@
 (a = 1, b = 2, c = 3)
 
 julia> getproperties((10,20))
-(10, 20)

Specification

getproperties belongs to the semantic level. getproperties guarantees a couple of invariants. When overloading it, the user is responsible for ensuring them:

  1. getproperties should be consistent with Base.propertynames, Base.getproperty, Base.setproperty!. Semantically it should be equivalent to: julia function getproperties(obj) fnames = propertynames(obj) NamedTuple{fnames}(getproperty.(Ref(obj), fnames)) end
  2. getproperties is defined in relation to setproperties so that:
    obj == setproperties(obj, getproperties(obj))
    The only exception from this semantics is that undefined properties may be avoided in the return value of getproperties.

Implementation

getproperties is defined by default for all objects. It should be very rare that a custom type MyType, has to implement getproperties(obj::MyType). Reasons to do so are undefined fields or performance considerations.

source
ConstructionBase.setpropertiesFunction
setproperties(obj, patch::NamedTuple)

Return a copy of obj with properties updated according to patch.

Examples

julia> using ConstructionBase
+(10, 20)

Specification

getproperties belongs to the semantic level. getproperties guarantees a couple of invariants. When overloading it, the user is responsible for ensuring them:

  1. getproperties should be consistent with Base.propertynames, Base.getproperty, Base.setproperty!. Semantically it should be equivalent to: julia function getproperties(obj) fnames = propertynames(obj) NamedTuple{fnames}(getproperty.(Ref(obj), fnames)) end
  2. getproperties is defined in relation to setproperties so that:
    obj == setproperties(obj, getproperties(obj))
    The only exception from this semantics is that undefined properties may be avoided in the return value of getproperties.

Implementation

getproperties is defined by default for all objects. It should be very rare that a custom type MyType, has to implement getproperties(obj::MyType). Reasons to do so are undefined fields or performance considerations.

source
ConstructionBase.setpropertiesFunction
setproperties(obj, patch::NamedTuple)

Return a copy of obj with properties updated according to patch.

Examples

julia> using ConstructionBase
 
 julia> struct S
            a
@@ -112,7 +112,7 @@
     @assert obj′′.$p₂ == w₂
     ...
     @assert obj′′.$pₙ == wₙ
-end

Implementation

For a custom type MyType, a method setproperties(obj::MyType, patch::NamedTuple) may be defined. When doing so it is important to ensure compliance with the specification.

  • Prefer to overload constructorof whenever makes sense (e.g., no getproperty method is defined). Default setproperties is defined in terms of constructorof and getproperties.

  • If getproperty is customized, it may be a good idea to define setproperties.

Warning

The signature setproperties(obj::MyType; kw...) should never be overloaded. Instead setproperties(obj::MyType, patch::NamedTuple) should be overloaded.

source

Tips for designing types

When designing types from scratch, it is often possible to structure the types in such a way that overloading constructorof or setproperties is unnecessary in the first place. It let types in your package work nicely with the ecosystem built on top of ConstructionBase even without explicitly depending on it. For simple structs whose type parameters can be determined from field values, ConstructionBase works without any customization, provided that the "type-less" constructor exists. However, it is often useful or required to have type parameters that cannot be determined from field values. One way to solve this problem is to define singleton types that would determine the type parameters:

abstract type OutputBy end
+end

Implementation

For a custom type MyType, a method setproperties(obj::MyType, patch::NamedTuple) may be defined. When doing so it is important to ensure compliance with the specification.

  • Prefer to overload constructorof whenever makes sense (e.g., no getproperty method is defined). Default setproperties is defined in terms of constructorof and getproperties.

  • If getproperty is customized, it may be a good idea to define setproperties.

Warning

The signature setproperties(obj::MyType; kw...) should never be overloaded. Instead setproperties(obj::MyType, patch::NamedTuple) should be overloaded.

source

Tips for designing types

When designing types from scratch, it is often possible to structure the types in such a way that overloading constructorof or setproperties is unnecessary in the first place. It let types in your package work nicely with the ecosystem built on top of ConstructionBase even without explicitly depending on it. For simple structs whose type parameters can be determined from field values, ConstructionBase works without any customization, provided that the "type-less" constructor exists. However, it is often useful or required to have type parameters that cannot be determined from field values. One way to solve this problem is to define singleton types that would determine the type parameters:

abstract type OutputBy end
 struct Mutating <: OutputBy end
 struct Returning <: OutputBy end
 
@@ -171,4 +171,4 @@
 
 # output
 
-true
+true diff --git a/dev/search/index.html b/dev/search/index.html index 1657904..cb60349 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · ConstructionBase.jl

Loading search...

    +Search · ConstructionBase.jl

    Loading search...