Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide hooks to massage data after creation #52

Open
djsegal opened this issue Apr 21, 2018 · 12 comments
Open

Provide hooks to massage data after creation #52

djsegal opened this issue Apr 21, 2018 · 12 comments

Comments

@djsegal
Copy link

djsegal commented Apr 21, 2018

If you have mutable structs, you can have fields you want to set before or after the constructor Parameters.jl uses.

Is there a way to provide access to wrapping that function?

Maybe with @before_create and @after_create (hook) macros?

@mauro3
Copy link
Owner

mauro3 commented Apr 22, 2018

I don't quite understand. Would it be solved with "Calculated fields" #18?

Also note that if you specify the positional constructor (for all fields) then the kw-constructur will run through that. That may allow to manually program what you're after.

@TsurHerman
Copy link

@mauro3
MWE would be a way to add finalizers to constructed mutable structs

@mauro3
Copy link
Owner

mauro3 commented Apr 25, 2018

But can't you provide finalizers with just registering a function: https://docs.julialang.org/en/stable/stdlib/base/#Base.finalizer: finalizer(::MyStruct, finalfn)? I don't see how adding macro magic to that would make it more concise or more readable.

@TsurHerman
Copy link

When do you add a finalizer? Usually at object creation time.
Otherwise I have to manually add a finalizer every time I construct a new object.

@mauro3
Copy link
Owner

mauro3 commented Apr 25, 2018

Thanks, now I get it. I think the post-create hook could be ok to implement as that would be a hook of a function of one argument. The pre-create hook however (I think) would need to be a function which has all fields as positional arguments, so it would not be any easier to write than the positional constructor.

So, for the post-create hook

@macroexpand @with_kw struct A
    a=1
    b=2
    @post_create a -> finalizer(a, finalfn) # post_create_fn =  a -> finalizer(a, finalfn)
end

struct A
    a
    b
    A(; a=1, b=2) = begin
        A(a, b)
    end
    A(a, b) = begin
        post_create_fn(new(a, b))
    end
end

I never had an application for this so it's low on my priority list. But a PR, if it does not add too many LOCs, would be welcome.

@djsegal
Copy link
Author

djsegal commented Aug 16, 2018

Current workaround is making data structure have one not-parameterized field and then using a base constructor that accepts at least one argument (i.e. the non-parameterized one)

This is related to the following line of code:

@mauro3
Copy link
Owner

mauro3 commented Aug 20, 2018

I don't understand that work-around, maybe you can post a MWE. What do you mean with "base constructor"? An inner or outer constructor?

@mauro3
Copy link
Owner

mauro3 commented Aug 20, 2018

If the pre-create hook would be just a block of code to be inserted into the positional inner constructor, then it would have access to all variables. Something like:

@macroexpand @with_kw struct A
    a=1
    b=2
    @pre_create begin
       println("Before `new`")
       a = a+1
    end
    @post_create a -> finalizer(a, finalfn) # post_create_fn =  a -> finalizer(a, finalfn)
end

struct A
    a
    b
    A(; a=1, b=2) = begin
        A(a, b)
    end
    A(a, b) = begin
        begin
           println("Before `new`")
           a = a+1
        end
        post_create_fn(new(a, b))
    end
end

Unfortunately, this makes the pre and post hooks asymmetric...

@mauro3
Copy link
Owner

mauro3 commented Jan 25, 2019

Another use case from #72 is to add a deprecation warning to a field:

struct AB
    a
    b
end

function AB(a,b)
    depwarn("b is deprecated", :AB)
    return AB(a)
end

@mauro3 mauro3 pinned this issue Jan 25, 2019
@djsegal
Copy link
Author

djsegal commented Mar 25, 2019

I don't think having symmetric pre/post hooks is that important?

One ultimate use case might be something like:

@with_kw struct Wire
  ...
  eta_cu = 1424
  eta_ss = 137
  w = 15
  ...
  dr = h_C
  N = round( ( r_2 - r_1 ) / dr - 1 )
  s_0 = 0.5 * ( r_1 + r_2 )
  ...
  function f_s(a,s)
      ...
  end

  function eta_para(J_para,a,s)
      ...
  end
  ...
end

@mauro3
Copy link
Owner

mauro3 commented Mar 25, 2019

I'm a bit confused by the question you ask yourself.

The example you give seems closer to calculated fields, no? Or what is a and s?

@mauro3
Copy link
Owner

mauro3 commented Nov 23, 2019

This would also be the way to generalize what macros (and other code) do inside the type-def. Currently @assert is special cased, such that it gets added to the constructor. Could there be a general way to do this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants