29
$\begingroup$

Existence of this topic is discussed in this mathematica.meta post.


I'm sure I am not the only non-beginner in WL who from time to time finds themselves not being able to predict an outcome of a specific function or being surprised it returned something. E.g.:

FileExistsQ[""] (*unevaluated + message*)

I'm talking about cases which have in common that such problematic outcomes could be considered an exception from a convention/best practices, or even an apparent bug. Sometimes they are just that, and sometimes there is a deeper explanation, deep enough not to be obvious when a problem occurs.

Anyway, the time is wasted on debugging or guessing which exceptions to handle.

A cheat-sheet with those cases can facilitate better programming.

Points to be fulfilled by an on-topic answer:

  • observed behavior deviates from the expected behavior

    based on either documentation or a pattern established by other functions, please provide links or explanation.

  • documented/officially supported features

  • features that in principle work correctly/as designed

What is NOT on topic:

  • bug reports

    (we should consider allowing exposing bugs reported n versions earlier and still affecting poor programmers)

  • backward incompatible changes

    there is a separate thread for this: Incompatible Changes since Mathematica Version 7?

  • very localized/subjective report

    (need to think how to define them well as the line is blurred here)

An example is worth 1000 words so I will start with the case of ...Q functions. The whole thread is meant to be community wiki so feel free to suggest/make edits.


Index:


Related links:

$\endgroup$
  • $\begingroup$ Candidates for inclusion? (1699), (108231), (119223), $\endgroup$ – Mr.Wizard Oct 29 '18 at 16:13
  • $\begingroup$ @Mr.Wizard I am not sure, I feel like they are closer to common piftalls than to bugs/broken conventions that I aim here. But I need to think about it. At the end everyone is free to post here so I will certainly not mind it. $\endgroup$ – Kuba Oct 29 '18 at 20:46
  • $\begingroup$ I'm not sure either, I put them to your attention and trust your judgement. I'll link anything else that comes to mind, with the same intent. $\endgroup$ – Mr.Wizard Oct 30 '18 at 2:14
17
$\begingroup$

...Q functions that can return something else than True or False

TL;DR;

Those exceptions return unevaluated or $Failed which needs handling.

Or if you don't want to think about that and only True is what matters then use TrueQ[] along with these predicate functions, e.g. TrueQ[FileExistsQ[filename]].

It may not be a complete list yet, but here's a start:

  • FileExistsQ
  • DirectoryQ
  • GeoWithinQ
  • ImageInstanceQ
  • SocketReadyQ

Following two just coincidentally have Q at the end but let's include it here even if they are clear as exceptions.

  • EllipticNomeQ
  • InverseEllipticNomeQ

Further reading:

One can be beaten by:

FileExistsQ[""] 

FileExistsQ::fstr: File specification is not a string of one or more characters.

FileExistsQ[""]

Why it can be surprising:

An important feature of all the Wolfram Language property-testing functions whose names end in Q is that they always return False if they cannot determine whether the expression you give has a particular property.

- tutorial/PuttingConstraintsOnPatterns

How to find them? One way is to investigate messages (except usage):

Select[
  {#, Column@
      DeleteCases[Messages@Evaluate@ToExpression[#], 
       HoldPattern[
         Verbatim[HoldPattern][MessageName[_, "usage"]]] :> _]} & /@ 
   Names["*Q"]
  , #[[2]] =!= Column[{}] &
  ] // Grid[#, Alignment -> {Left, Top}] &

It maybe makes sense to return $Failed in case of connection problems, but I'd say it is better not to name your function with ...Q if it needs e.g. internet connection.

messages associated with *Q functions

$\endgroup$
  • 5
    $\begingroup$ A corollary of this is that for safety, one might want to use TrueQ[] along with these predicate functions, e.g. TrueQ[FileExistsQ[filename]]. $\endgroup$ – J. M. is away Nov 14 '17 at 10:15
  • 5
    $\begingroup$ To me, this clearly looks like a consequence of the absence of exception-handling practices in idiomatic Mathematica (meaning, as recommended by the docs). The Q - predicates should return True or False, but when the input is invalid, it would make much more sense to throw an exception (which would be a much clearer semantics),than to remain unevaluated (which expressly breaks the Q contract) and issue a message. But for that, it should be possible to document that functions can throw exceptions, and that would require a better-integrated into the language exception-handling mechanism. $\endgroup$ – Leonid Shifrin Nov 14 '17 at 19:53
  • 2
    $\begingroup$ Another thing I forgot to mention: recall that If[] has a four argument form, where the first three arguments are the usual ones and the fourth one is the statement to evaluate if the predicate does not return True or False. This is one more possibility for the exception handling indicated by Kuba in the answer above. $\endgroup$ – J. M. is away Nov 15 '17 at 1:31
  • $\begingroup$ EllipticNomeQ never returns True or False. $\endgroup$ – Michael E2 Oct 30 '18 at 2:12
  • $\begingroup$ @MichaelE2 interesting exceptions :) $\endgroup$ – Kuba Oct 30 '18 at 8:30
8
$\begingroup$

Support for Directory[]

This was always puzzling me but I'm happy to delete this answer if I'm alone in this.

TL;DR;

Functions that do NOT respect Directory[]:

  • NotebookOpen (*1*)
  • NotebookLocate (*1*)
  • NotebookSave (*2*)

  • SystemDialogInput

  1. Respects CurrentValue[NotebookPath] quick fix is to e.g. NotebookOpen @ AbsoluteFileName @ _

  2. Respects the most recent notebook saving directory! You need to FileNameJoin + Directory[]

Functions that DO but one might not expect that knowing cases above:

  • NotebookImport (*!*)
  • CDFDeploy

Motivation

I came to this neighbourhood as of Mathematica V7 and I didn't have much experience with command line etc. In this context the border between the Kernel and the FrontEnd was very blurred at the beginning.

It took me quite a while to get used to that and even though I can explain it now, I am still claiming it is confusing.

The more that ref / NotebookPath:

This function has not been fully integrated into the long-term Wolfram Language, and is subject to change.

$\endgroup$
6
$\begingroup$

Exceptions in the standard stylesheet/style inheritance stack

Quick list of deviations

Feel free to add anything, try to make it short and if needed add examples or more explanation at the end of the answer.

  • "DockedCell" style is inserted in every DockedCell before any explicit style.

    So either you overwrite "DockedCells" in your stylesheet or use explicit options in Cell, see "DockedCell" example.

  • "InlineCell" same story but less problematic as "InlineCell" styles are less invasive. So keep that in mind when defining custom DefaultInlineCellStyle.

  • "InlineCellEditing" as above if you want to adjust/switch of orange-ish background that appears during edition you need to modify this style even even for custom DefaultInlineCellStyle

  • All style + FormatType issue, see topic linked below for full explanation. TL;DR;? better do not use All.

Points from above, with a little background, are mentioned in Order/Dependency of Styles in a Stylesheet.

  • Button(Box)'s Appearance is inserted explicitly during typesetting

    which makes it impossible to set Button's appearance via a stylesheet or style with outer ButtonBoxOptions. You need to set Appearance -> Inherited to do so. See Button Appearance example.

  • cell's top CellMargin behavior in presence of PageBreakAbove -> True in that cell.

    See: 154542. Quick fix is to add CellElementSpacings -> {"ClosedGroupTopMargin" -> 100} option.

  • : notebook's WindowSize->All ignores the very bottom CellMargins

    see more in 112593

  • DockedCell on Windows can't be White 160356

Motivation

The idea and scheme is quite simple see: tutorial / WorkingWithStylesheets / Inheritance

But there is no way to check where current setting for e.g. FontSize comes from. Which makes 'debugging' styles extremely painful. Any exception from the simple scheme makes it even worse, that is why one needs to know what to expect.

Examples

- "DockedCell"

CreateDocument[{},
 DockedCells -> Cell["test", "myDockedCell"],
 StyleDefinitions -> Notebook[{
    Cell[StyleData[StyleDefinitions -> "Default.nb"]],
    Cell[StyleData["myDockedCell"], Background -> Red, FontSize -> 30]
    }]
 ]

The docked cell is gray despite stylesheet Background spec for myDockedCell, FontSize works well. That is because "DockedCell" style has Background option.

So every Cell[content, style, opts] inside DockedCells effectively becomes Cell[content, "DockedCell, style, opts]...

- Button Appearance

Style[
 Button["LabeL", Print[1]],
 ButtonBoxOptions -> {ImageSize -> {200, 200}, Appearance -> "FramedPalette"}
]

ImageSize is respected but Appearance not, you need Button["LabeL", Print[1], Appearance -> Inherited] to make it work but then you ask yourself, why bother with nice setup and not create myButton function and put all stuff there?

Official classification of the issue: 116030#comment315233_116030

$\endgroup$
  • $\begingroup$ That Button one I never knew about. That's got the potential to cause some nasty confusion. $\endgroup$ – b3m2a1 Mar 4 '18 at 2:10
5
$\begingroup$

Arguments conventions for export like functions

It is not that tough yet I'm always confused, so again, if that is only me let me know and I will delete that answer.

Export[      "where", what, how]
CDFDeploy[   "where", what]
Write[       "where", what..]
WriteString[ "where", what..]
LinkWrite[   "where", what]
Save[        "where", what]
DumpSave[    "where", what]

Put[         what.., "where"]
PutAppend[   what.., "where"]    
CloudDeploy[ what, "where"]
CloudPut[    what, "where"]
CloudSave[   what, "where"]
CloudExport[ what, how, "where"]

So Put/PutAppend order and shuffled CloudExport are outliers one has to keep in mind.

$\endgroup$
  • $\begingroup$ So to memorize: "Where is my PC? At the end (of the question)." The exceptional "C" is a legacy one. :) -- And, yes, it is confusing so do not delete the answer please. $\endgroup$ – gwr Mar 23 '18 at 11:12
5
$\begingroup$

Exceptions to "first option's value takes precedence" rule

One usually expects expr[opt1 -> a, opt1 -> b] to be equivalent to expr[opt1 -> a]. At the end this is how Replace* functions work: opt1 /. {opt1 -> a, opt1 ->b } returns a.

Thare are exceptions where the last one is chosen though, mostly related to a FrontEnd.

Many of them are related to controllers because of how they are implemented. They don't use OptionValue to extract options but something along those lines:

controller[_Dynamic, ___, specificOption -> specificValue, ___]:=...

See SaveDefinitions example, you can always lookup definitions with PrintDefinitions.

  1. StyleDefinitions option for notebooks

  2. SaveDefinitions -> False for DynamicModule

(* in construction *)

Code samples:

Ad 1.

CreateDocument[Pane["Test", 600],     
 StyleDefinitions -> "Dialog.nb", StyleDefinitions -> "Default.nb",     
 WindowTitle      -> "A dialog" , WindowTitle      -> "A notebook"
]

 (* Default.nb with "A dialog" title" *)

Ad 2.

 foo[]:=1;
 ToBoxes @ DynamicModule[{x}, Dynamic@foo[], SaveDefinitions -> False, SaveDefinitions -> True]

(* foo included! *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.