0
$\begingroup$

Suppose I'm using the expression Person[fn_String, ln_String] as a data expression, and want to prohibit the creation of expressions where PersonQ[person] is False.

Q: Is there an "elegant" way to implement this?

Attempts:

  1. I can create an additional function, say, CreatePerson[fn_String, ln_String] that only returns the Person expression if PersonQ is True. This does not prevent the creation of arbitrary Person expressions. Also, this feels like I'm missing something obvious.
  2. I've tried defining Person to be a function and return Person[fn,ln] as a deferred evaluation expression, but the head of this expression is not Person. That is, the FullForm is not Person[fn,ln]. Not ideal...
  3. I've created a Person[fn,ln] function that creates a String s="Person[fn,ln]" and then returns ToExpression[s], but this feels extremely hacky.

Am I missing something obvious?

Thanks!

$\endgroup$
2

2 Answers 2

0
$\begingroup$

I think that #1 is the way to go. There may be more contextual info to consider, but my suggestion is based on just what I can glean from your question. You can make this even more rigorous by using a "private" context. Let's say you're building a package. Maybe the package context is Stuff. You'd publicly declare CreatePerson (or NewPerson, or whatever), but the head of the thing returned would actually be in a specific context different from Global (which is where the user is probably operating). Maybe Stuff'Private'Person (those should be backticks, but I don't know how to make backticks visible here). You'd also have to publish the functions that operate on Stuff'Private'Person "objects". Nothing in Mathematica is truly private, but this is typically a sufficient degree of "private-ness". The users do things like myPerson = CreatePerson[fn, ln], and thereafter they just operate on myPerson, so they don't ever need to know the actual head of the expression (but if they want to, they can still muck stuff up--they just have to be very deliberate about it, and in that case caveat emptor).

$\endgroup$
0
$\begingroup$

Thank you for your reply! After exploring patterns some more, I did find another approach that I'm happy with.

  • I created a PersonQ[args_List] function.
  • For the Person expression, I then added validation using Person[args__/;!PersonQ[{args}]]:=Messages[Person::error];

This way the Person expression is created if it passes all the validation rules, while an error message is displayed otherwise.

$\endgroup$
8
  • $\begingroup$ I don't think this is a good way to go (but maybe something got lost in translation). First off, Messages is a built in function that expects a symbol. So the thing you're returning here is an overload of a semantically different thing. $\endgroup$
    – lericr
    Commented Feb 6, 2023 at 22:47
  • $\begingroup$ But maybe you meant Message (without the "s"). It's fine to emit a message like that, but what happens with Message is that it puts the message in the message "system" (I don't know what to call it) but the value it returns is Null. So, that accomplishes your goal, but it does it very aggressively. Having Nulls popping up spontaneously in other expressions could have unexpected (undesirable) consequences. $\endgroup$
    – lericr
    Commented Feb 6, 2023 at 22:48
  • $\begingroup$ This is very different than the way Mathematica behaves for system functions. Try Sin[1,2]. That's an unhandled form for Sin, and as one might expect, it generates a message. But it still returns the expression Sin[1,2]. $\endgroup$
    – lericr
    Commented Feb 6, 2023 at 22:50
  • $\begingroup$ Thank you for comments! I did use Message and not Messages - twas a typo. Returning Null is definitely a problem. And that's an excellent point that returning Null would probably require Null checks everyone which doesn't seem very "Wolframic."I've gone back-and-forth over whether or not any form of expression validation is required. For experienced users, providing a PersonQ function seems sufficient. But for beginners, I think a message would be helpful. Now to just figure out how to emulate the Sin[1,2] behavior! $\endgroup$ Commented Feb 6, 2023 at 23:25
  • $\begingroup$ Yeah, I didn't mean really to emulate Sin[1,2] exactly, just that some useful return value is nice (for some definition of useful, which oftentimes does come down to unchanged). $\endgroup$
    – lericr
    Commented Feb 6, 2023 at 23:37

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