Skip to content

Symbols Guide

Kuba edited this page Nov 16, 2018 · 3 revisions

Big picture

It is mostly about syntactic sugar for Catch/Throw to cope well with Messages/Failures.

Basic rules:

  • MGenerate, MGenerateAll, MThrow, MThrowAll have the same syntax with respect to Message/Failure related cases.
    • -All means that a Message will be issued too. That also implies only a valid message input can be used while simple MThrow can accept whatever input you give it.
    • Generate just creates e.g. a Failure while MThrow throws is to a nearest enclosing MCatch.

MThrow can take Message syntax with optional first element which will be a Failure's tag.

MCatch[     MThrow["500", General::invty, Method]    ]

Failure["500", <|"MessageTemplate" :> General::invty, "MessageParameters" -> {Method}|> ]

Replace MThrow with MThrowAll and a message will be issued.

Below is a more detailed symbols guide:

Core symbols

MFailureQ

MFailureQ /@ {
    $Failed, $Aborted, $Canceled, Failure["any","Message"->"Generic message"]
}

{True,True,True,True}

MGenerate, MGenerateAll, MThrow, MThrowAll, MCatch

Basic usage:

MGenerateAll[General::argt,foo,2,3,4]

General::argt: foo called with 2 arguments; 3 or 4 arguments are expected.

Failure["argt", <| "MessageTemplate" :> General::argt, "MessageParameters" -> {foo, 2, 3, 4} |> ]

Use custom tags for a more fine grained control flow:

MCatch @ MThrow["custom tag",General::argt,foo,2,3,4]

Failure["custom tag", <|"MessageTemplate" :> General::argt, "MessageParameters" -> {foo, 2, 3, 4}|>]

Association/Failure oriented syntax:

MCatch @ MThrow[foo::argx, <|"arg"->bar|>]

Failure["argx", <|"MessageTemplate" :> foo::argx, "MessageParameters" -> <|"arg" -> bar|>|>]

Adding payload can be invaluable for complex flow:

MCatch @ MThrow[
    "custom tag"
  , General::argt
  , foo,2,3,4
  , <|"Payload"->"additional information"|>
]

Failure[ "custom tag" , <|"MessageTemplate" :> General::argt , "MessageParameters" -> {foo, 2, 3, 4} , "Payload" -> "additional information" |> ]

MHandleResult

More idiomatic approach to If[Test @ expr, exception @ expr, expr]:

MCatch[
    $Aborted // MHandleResult[]; 1
]

Failure["err", <|"Message" -> "$Aborted"|>]

MCatch[
    NotAString[] // MHandleResult[
      Except[_String] , Function[res, MThrow[foo::string, Head[res], _String]]
    ]
  ]

Failure["string", <|"MessageTemplate" :> foo::string, "MessageParameters" -> {NotAString, _String}|> ]

M*OnFailure

More idiomatic approach to If[ FailureQ[expr], handler @ expr, expr]:

$Failed // MOnFailure[foo]

foo[$Failed]

MCatch[ $Failed // MOnFailure[MThrow] ]

$Failed

There is a shorter version for throwing though:

MCatch[ $Failed // MThrowOnFailure ]

$Failed

Function construction

I find unevaluated expressions hard to manage with respect to flow control so I would like always to get a Failure:

  foo[x_]:=x^2; 
  foo // MFailByDefault; 
  
  foo[1,2]

foo::argpatt: There are no rules associated with signature foo[Integer, Integer].

Failure["argpatt", <|"MessageTemplate" :> foo::argpatt, "MessageParameters" -> {"foo[Integer, Integer]"}|>]

Validation

The idea behind those utilities originates from https://mathematica.stackexchange.com/q/116571/5478

MValidate[
  <|"a" -> <|"b" -> 2, "c"->3, "d" -> 4|>|>
, KeyValuePattern[{"a" -> KeyValuePattern[{"b" -> _Integer, "c" -> _Integer, "d" -> _Integer}]}]  
]

True

MInvalidContents[
  <|"a" -> <|"b" -> 2, "c" -> 3|>|>
, KeyValuePattern[{
    "a" ->    KeyValuePattern[{"b" -> _Integer, "c" -> _String, "d" -> _List}]
  }]
]    
{ {Key["a"], Key["c"]} -> MValidationResult[False, Integer]
, {Key["a"], Key["d"]} -> MValidationResult[False, Missing[]]
}
foo // ClearAll
$fooPatt = KeyValuePattern[{"a" -> _Integer, "c" -> _String}];

foo // MValidateByDefault[ $fooPatt ]

foo[ in: $fooPatt]:= in["a"]

foo @ <|"a" -> 1, "c" -> "c"|>

foo @ <|"b" -> 1, "c" -> {1}|>

1

foo::InvalidArg: Argument No. 1 has invalid structure at:
  {Key[c]} List
  {Key[a]} Missing[]
It needs to match:
  <|a -> _Integer, c -> _String|>

Failure[...]

Utilities

ToKeyValue

Module[{x = 1, y = 2, z = "string"}, ToKeyValue @ {x,y,z}]

{"x" -> 1, "y" -> 2, "z" -> "string"}