Syntax for outer constructor and thow-away input argument

Hello there,

A simple semantic question, and a way to call an inner constructor
Assuming I have a simple structure defined as follows

struct Test 
   b::Int;
   m::Int;
   n::Int;
end 

But such that we have b = m+n+1. One can built an inner constructor to check that the construction is fine

struct Test 
   b::Int;
   m::Int;
   n::Int;
   Test(b::Int,m::Int,n::Int) = begin 
                     @assert b == m+n+1 "b should be m+n+1"
                     return new(b,m,n)
                   end
end 

And the structure can be called by

Test(8,0,7)

And raises an error with Test(8,0,4).

In some cases, I would like to be able to partially defined the structure, i.e call a Test(8,0,) that returns a Test(8,0,7) or Test(8,,7) that returns a Test(8,0,7). Kind of throw-away input argument.
However, I cannot figure out how to call such a function. I was thinking to define function as

Q(b::Int,m::Int,_) = Q(b,m,b-m-1);
Q(b::Int,_,n::Int) = Q(b,b-n-1,n);

But if definition is possible, I can’t instanciate them with

Test(8,0,_)
ERROR: syntax: all-underscore identifier used as rvalue

I understand the error, and

  • I know that I can handle the construction using keyword
  • Can also define Test(8,0,nothing) that can be handled by multiple dispatch, but I was wondering if such an easy syntax as Q(8,0,) or Q(8,,7) can be used ?
    Any advice ?

Thanks

_ is not a value you can use (rvalue), it is syntax for ignoring values. This is what the error message says.

I would suggest that you have a Test(; b, m, n) outer constructor that just fills in the value not provided. range is a example you can follow for the implementation.

An alternative is to define a singleton struct, eg

struct FillIn end

Q(b::Int, m::Int, ::FillIn) = Q(b,m,b-m-1)

# call as Q(b, m, FillIn())

(incidentally, lines do not need to be terminated with ; in Julia)

Maybe you could use a colon (:) as placeholder for a missing value?

Q(b, m, n) = (b=b, m=m, n=n)
Q(b::Int, m::Int, ::Colon) = Q(b, m, b-m-1);
Q(b::Int, ::Colon, n::Int) = Q(b, b-n-1, n);
julia> Q(8, 0, :)
(b = 8, m = 0, n = 7)

julia> Q(8, :, 7)
(b = 8, m = 0, n = 7)

Such a syntax is consistent with what is done for example in reshape when one does not want to specify all arguments.

1 Like

@Tamas_Papp Thanks for the answer. Outer is indeed a good solution there, even if I prefer the second approach with the specific type handler. For the ;, I am affraid that it is some PTSD from former langages !

@ffevotte Many thanks, this is exaclty what I was looking for !