7
\$\begingroup\$

Recently, an answer of Peter Taylor here says:

To get a macro equivalent to

f(n){n=n?:1;}

you need

-Df(n)=((n)?:1)

which is longer, so there's no point.

So are those criteria really necessary? Which of the following criteria should be satisfied:

  • Arguments must be put in parentheses.
  • The function itself must be wrapped in parentheses (unless it's single token).
  • The argument must be referenced exactly once.
  • There should be a trailing newline (if use #define) (because you can't put the code right after the macro, you need a trailing newline).
  • If there are multiple statements there should be if(1){...}else wrap or do{...}while(0) wrap.

Real world macros satisfy all three of them (except some nonstandard ones (never used in production code), for example the macro defined by

#define all(x) begin(x), end(x)

. With this you can do some (weird?) trick such as

sort(all(x))

, which avoid duplication of x in code - source: this or this)


Should that be enforced?

  • Agree: That's the standard of C macro.
  • Agree: That makes the macro more like a real "function".
  • Disagree: That may change a lot of existing submissions.
  • Disagree: Even without that condition, we can call it with variables, and wrap the return value in parentheses. This is "require more input than necessary".
  • Disagree: That takes more bytes. (← should not be a problem)
\$\endgroup\$
5
  • \$\begingroup\$ Requiring parentheses around the macro body would probably invalidate most existing C macro submissions. I don't think it should be required for code golf. \$\endgroup\$
    – Steadybox
    Commented Dec 21, 2017 at 2:24
  • \$\begingroup\$ I don't understand the syntax of your last parenthetical. It seems like you are missing a word or two. \$\endgroup\$
    – Wheat Wizard Mod
    Commented Dec 21, 2017 at 9:00
  • 1
    \$\begingroup\$ In addition, you're asking the wrong question. The answer to "How should a C macro be scored?" is by counting the bytes, the same as for any other type of answer. The question you're actually asking is "What must a C macro do to be a valid answer?" \$\endgroup\$ Commented Dec 21, 2017 at 9:34
  • \$\begingroup\$ @WheatWizard Which "parenthetical" are you referring to? \$\endgroup\$
    – user202729
    Commented Dec 21, 2017 at 11:27
  • \$\begingroup\$ in particular the phrase "like <code> macro, then you can do something like <code>", unless I'm missing something (which I very well might be) I don't think that is a grammatical sentence, and I'm not even really sure what is trying to be said. \$\endgroup\$
    – Wheat Wizard Mod
    Commented Dec 21, 2017 at 19:36

2 Answers 2

5
\$\begingroup\$

As I see it this is quite simple: the default submission format is program or function, including function-like constructs. Since C has functions, a function-like construct in C should be interchangeable with a function, so if there are expressions where substituting a valid function with the given macro would change the behaviour, the macro is not a valid answer.

\$\endgroup\$
8
  • 1
    \$\begingroup\$ About "The argument must be referenced exactly once", it's so that the macro would be exactly equivalent to its functional counterpart, in case the argument has side effect, e.g. f(++i) or f(i++). \$\endgroup\$
    – user202729
    Commented Dec 21, 2017 at 11:28
  • \$\begingroup\$ Ah, that makes sense. I'll delete my comment on the question. \$\endgroup\$ Commented Dec 21, 2017 at 11:47
  • \$\begingroup\$ Another issue: What should be done with existing answers? That may be a different question, however. I think just keep it, but enforce this rule with newer answers. \$\endgroup\$
    – user202729
    Commented Dec 21, 2017 at 12:24
  • 2
    \$\begingroup\$ I'm not sure how many existing answers there are, but I don't see this as saying anything new but merely restating existing policy, and I don't think that being older than this answer should exempt existing answers from following policy which predated them. \$\endgroup\$ Commented Dec 21, 2017 at 12:37
  • 2
    \$\begingroup\$ Go back to function, I think int f(int&n) in C++ should be allowed, though it can't handle situations that input is a const or an expr \$\endgroup\$
    – l4m2
    Commented Dec 21, 2017 at 22:05
  • \$\begingroup\$ @l4m2, in the context of this answer that looks like an argument that macros should support passing by value or reference, but I suspect that may not be your intention. \$\endgroup\$ Commented Dec 22, 2017 at 13:40
  • 1
    \$\begingroup\$ Even in that case, a ? x : y is a completely valid lvalue in C++. There is no language restriction that can force the input to be atomic. \$\endgroup\$
    – user202729
    Commented Dec 23, 2017 at 11:14
  • \$\begingroup\$ I also define macro that convert variable to pointer, to simplify some program(e.g. rewrite a realloc int rerealloc(void*&ptr, size_t len), in a layer of macro) \$\endgroup\$
    – l4m2
    Commented Dec 27, 2017 at 9:33
5
\$\begingroup\$

It must work

I can't say I'm even moderately versed in this "C macro passed directly to the compiler" concept, but in code golf the main requirement for an answer to be valid is just that it defines a function or program which solves the challenge. We very much do NOT care about best practices as long as your compiler or interpreter doesn't enforce them.

For example, in a comment you mention that the argument of the function should show up exactly once in the macro to avoid extra side effects that would cause different behavior compared to defining the function normally. Code golf doesn't care unless it causes problems for that exact challenge. Most of the time your inputs would be literal values with no side effects anyway. As long as the compiler doesn't complain and the "function" can be called and works, then it remains valid.

Taking your example, the macro code seems to define a function (or function-like construct) f(n). If I want to call the function on a value x inside a program, and then store the return value in a variable y, I would write y = f(x);. As long as the macro results in that line being valid and resulting in y correctly containing the same result as any other valid answer would, then whatever "code" was passed to the compiler to define that "function" is a valid answer itself.

One thing specifically though: I would probably NOT allow a function to be defined in a way that calling it requires y = (f(x)); instead. Those parentheses should be in the source code if they are needed for the function to work.

\$\endgroup\$
9
  • \$\begingroup\$ But who says that you can't call function f with argument 5 by int x = 4; f(x++ + 1);? \$\endgroup\$
    – user202729
    Commented Dec 21, 2017 at 16:09
  • 3
    \$\begingroup\$ @user202729 If the challenge requires answers to operate on "expressions that evaluate to n" and not just "n" then it should specify that. \$\endgroup\$ Commented Dec 21, 2017 at 16:12
  • 1
    \$\begingroup\$ For many languages there isn't even definition what is an expression... Also use the result as rvalue temporary is actually quite common, what if I want to not just store it to a temporary variable but instead do something else? Doing printf("%d", f(x) + 1) is also common. \$\endgroup\$
    – user202729
    Commented Dec 21, 2017 at 16:14
  • 3
    \$\begingroup\$ @user202729 To put things more broadly, challenges require things that they say they require. If the challenge states that answers must cause printf("%d", f(x) + 1) to behave a certain way then answers must cause that to behave a certain way (though I suspect it will be poorly received because language restrictions are unpopular). If the challenge just says "Do X" then an answer which defines a function f which is called like y = f(n); and leaves the result in y is acceptable, even if there are other situations that would cause it to break. \$\endgroup\$ Commented Dec 21, 2017 at 16:20
  • 1
    \$\begingroup\$ "challenges require things that they say they require" is true but incomplete. There are (possibly too many, but that's a separate issue) other things which challenges require unless they say otherwise, to avoid each challenge having so much boilerplate that people have to use diff to find the interesting content. That's what most of policy is about. \$\endgroup\$ Commented Dec 21, 2017 at 17:36
  • \$\begingroup\$ @PeterTaylor And does anything policy indicate that solutions must work for every possible format of invocation that the language supports? \$\endgroup\$ Commented Dec 21, 2017 at 18:17
  • \$\begingroup\$ Have you even read my answer? \$\endgroup\$ Commented Dec 21, 2017 at 19:41
  • 1
    \$\begingroup\$ @PeterTaylor I did read your answer, I didn't actually COMPREHEND your answer until just now, nor did I notice that you were the poster of that answer. I explicitly disagree with that answer now that I understand it. \$\endgroup\$ Commented Dec 21, 2017 at 19:52
  • 2
    \$\begingroup\$ Go back to function, I think int f(int&n) in C++ should be allowed, though it can't handle situations that input is a const or an expr \$\endgroup\$
    – l4m2
    Commented Dec 21, 2017 at 22:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .