Is multiple dispatch the best way to handle multiple possible combinations in a package?

Hi Julia people,

I’m currently working on a major update for my package ‘RayTraceHeatTransfer.jl’. I want the updated package to contain the following features (many of which are new):

  • 1D/2D/3D geometry (user can define either a 1D, 2D or a 3D geometry (3D will be meshed using TetGen.jl))
  • Selective/Uniform geometry-sampling (the selective is for sampling based on boundary conditions, uniform is for uniform accuracy (no apriori knowledge of boundary conditions))
  • Uniform/Nonuniform gas properties (affects ray tracing)
  • In the case of ‘Uniform gas properties’ I want to include a check for transparency (and for domain convexity), and if below a certain treshold, I want to calculate view factors analytically between surfaces.

I have been considering whether there is an ‘optimal’ way to handle the many possible combinations (I counted at least 12 unique) between the above possibilities? Would the smartest way be to just use multiple dispatch and create separate functions for each case? Or is there a smarter way to go around this?

Kind regards, Nikolaj

Generally, the way is to separate into a few cases, and then have the function that the function itself calls do a few extra dispatches and so on. Multiple dispatch is really flexible. You do not need to have 12 different methods for 12 cases. You can have a few methods that call a few methods that dispatch to the appropriate response.

1 Like

I’d say that multiple dispatch is well suited for this problem but perhaps there is a way to reduce the combinatorial explosion by designing the methods in a clever way.

I’ll try to make an example loosely based on this you described (I don’t know anything about he actual algorithms). Say we have types like this:

abstract type AbstractGeometry end
struct Geometry1D <: AbstractGeometry end
struct Geometry2D <: AbstractGeometry end
struct Geometry3D <: AbstractGeometry end

abstract type AbstractSampling end
struct UniformSampling <: AbstractSampling end
struct SelectiveSampling <: AbstractSampling end

Instead of having 6 methods for each combination of an AbstractGeometry and AbstractSampling try to instead write a generic function that describes the sampling procedure and only like “fill in the blanks” with different behavior based on the types passed. So say you want to generate a some ray for tracing, then you might have a single function

function generateRay(::UniformSampling, geometry)
    # just choose a random starting point and direction
    dims = dimensions(geometry) # this is method that each subtype of AbstractGeometry implements and just gives the number of dimensions
    return Ray(randn(d), normalize!(randn(d))
end

function generateRay(::SelectiveSampling, geometry)
    # i am assuming that the boundary condition is some property of the geometry
    boundary = find_boundary(geometry)
    # ... some computation to find starting point
end

So ideally instead of having M*Ncombinatorially many methods, so just need M+N methods which are used to “fill in the blanks” in a generic implementation. I hope that makes sense :slight_smile:

3 Likes