JuliaApproximation / DomainSets.jl

A Julia package for describing domains as continuous sets of elements
MIT License
72 stars 12 forks source link

use `getindex` for UnionDomain and ProductDomain? #79

Closed daanhb closed 3 years ago

daanhb commented 3 years ago

Currently, composite structures in DomainSets are queried using numelements, elements(object) and elements(object, i). This is done to avoid possible conflict with the use of getindex for certain domains. The element functions are used in packages downstream, typically composite array-like objects, where getindex does refer to the entries of the array and not to the list of composing objects.

Still, this is a non-standard thing to do, and implementing getindex for UnionDomain may not actually conflict with anything.

On the other hand, a UnionDomain acts like a set of domains more than like an array, and Set does not implement getindex because the ordering shouldn't matter. Also, in some cases, (like 2 .+ (0..1)), we think of domains like an infinite array of points, and perhaps that interpretation does lead to conflicts if some domains are an array of domains and others are not. Right now, the BroadcastStyle of a domain is DomainSetStyle to support this.

On the plus side, with the more standard getindex, it would probably become easier to manipulate composite domains with standard tools.

daanhb commented 3 years ago

It seems ApproxFun uses components for this? @dlfivefifty There could be a generic components function, and a getcomponent(A, I...) which defaults to getindex(components(A), I...). That may make a lot of getindex machinery available.

dlfivefifty commented 3 years ago

I used component(A, I...) for components(A)[I...] though getcomponent may also make sense. Given the very narrow use of get* and set* in Julia, see below autocomplete, I've always viewed getindex and setindex as an anachronism, but that's really just a personal preference.

julia> get

get                 getfield             getkey
get!                gethostname          getpid
get_zero_subnormals getindex             getproperty

julia> set

set_zero_subnormals setenv               setprecision
setdiff             setfield!            setproperty!
setdiff!            setindex!            setrounding
daanhb commented 3 years ago

Good point, I'd favour component over getcomponent because it is shorter... You don't typically spell out getindex very often. I'm trying out a simple CompositeTypes.jl package to implement this in general. It is worth doing well, because it could also contain a generic way of displaying composite structures (an implementation of show(io, object)), which is a lot harder to do and @roelmatthysen had a very nice implementation technique for that.

daanhb commented 3 years ago

See CompositeTypes.jl: the package defines iscomposite, components, ncomponents, component(x, I...) and (if applicable) setcomponent!(x, v, I...). Does that look like a plan?

daanhb commented 3 years ago

The package also defines indexing and display, but that is opt-in only: using CompositeTypes.Indexing and using CompositeTypes.Display. For DomainSets.jl, the display routines result in something like:

julia> boundary(UnitCube())
D₁ ∪ D₄ ∪ D₃

D₁ = D₂ × (0.0..1.0 (Unit)) × (0.0..1.0 (Unit))
D₂ = Point{Float64}(0.0) ∪ Point{Float64}(1.0)
D₃ = (0.0..1.0 (Unit)) × (0.0..1.0 (Unit)) × D₂
D₄ = (0.0..1.0 (Unit)) × D₂ × (0.0..1.0 (Unit))

This is used when a multi-line description of the object is possible. The shorter description in a single line is

julia> show(stdout, boundary(UnitCube()))
((Point{Float64}(0.0) ∪ Point{Float64}(1.0)) × (0.0..1.0 (Unit)) × (0.0..1.0 (Unit))) ∪ ((0.0..1.0 (Unit)) × (Point{Float64}(0.0) ∪ Point{Float64}(1.0)) × (0.0..1.0 (Unit))) ∪ ((0.0..1.0 (Unit)) × (0.0..1.0 (Unit)) × (Point{Float64}(0.0) ∪ Point{Float64}(1.0)))

This is not quite right yet, though closer to being correct than what is currently displayed. (Edited, I fixed the parentheses in the expression.)

daanhb commented 3 years ago

Conclusion, for now I went with CompositeTypes in v0.5. Any indexing one would like to do on composite domains can be done on components(domain) instead.