I'm settling in on a programming pattern for "constructors." I can illustrate the pattern with the following example, which defines a constructor newBar for "objects"-as-Associations of type bar:
ClearAll[bar, newBar];
Options[newBar] = {"a" -> 42, "b" -> 43};
newBar[OptionsPattern[]] := <|"a" -> OptionValue["a"], "b" -> OptionValue["b"]|>
?? newBar
Global`newBar newBar[OptionsPattern[]]:=Association[a->OptionValue[a],b->OptionValue[b]] Options[newBar]={a->42,b->43}
newBar[]
<|"a" -> 42, "b" -> 43|>
newBar["b" -> 117]
<|"a" -> 42, "b" -> 117|>
This does a nice job of supplying default values. The only downside is that there is LOTS of repitition in the boilerplate, and I'd like to abstract that out. Here's an almost-working attempt:
ClearAll[capitalize];
capitalize[string_String] :=
With[{chars = Characters[string]},
StringJoin[Prepend[Rest[chars], ToUpperCase[First[chars]]]]];
capitalize["foo"]
"Foo"
ClearAll[camelback];
camelback[strings_List] :=
StringJoin@Prepend[capitalize /@ Rest[strings], First[strings]];
Symbol@camelback[{"new", "foo"}]
newFoo
ClearAll[constructor];
constructor[nym_Symbol, attributes_Association] :=
With[{keys = Keys[attributes],
values = Values[attributes],
cNym = Symbol@camelback[{"new", ToString[nym]}]},
ClearAll[cNym];
Options[cNym] = Normal[attributes];
cNym[OptionsPattern[]] :=
Evaluate@Association[
MapThread[Rule, {keys, OptionValue /@ keys}]]
];
constructor[foo, <|"a" -> 1, "b" -> 2|>]
?? newFoo
Global`newFoo newFoo[OptionsPattern[]]:=<|a->OptionValue[a],b->OptionValue[b]|> Options[newFoo]={a->1,b->2}
So far, so good. It looks very similar to the bar example. The most notable difference is the <|...|> notation instead of the call to Association, and that seems to be the clue, but I can't interpret the clue. In any event, it doesn't work, presumably because OptionValue doesn't get evaluated at the right time.
newFoo["a" -> 42]
<|"a" -> OptionValue["a"], "b" -> OptionValue["b"]|>
Any advice?
OptionValueto(OptionValue[#]&), and has indeed to do with how / whenOptionValueis evaluated. There has been a discussion on that, I will try to find a link. – Leonid Shifrin Oct 15 '14 at 17:21Evaluate@Association[MapThread[Rule, {keys, OptionValue /@ keys}]]toAssociation[MapThread[Rule, {keys, OptionValue[#]&/@ keys}]]and it works :) Promote to an answer and I'll accept it. Thanks much! – Reb.Cabin Oct 15 '14 at 19:21OptionValue. – Leonid Shifrin Oct 15 '14 at 19:31