It's funny to see but this is just documentation for a COM API function that runs a macro with any number of arguments (depending on the macro you want to run). That's why it doesn't use a typesafe delegate or something more clear but a lot of ugly "object"s; it has to pull it off with the lowest common denominator for .NET and COM. It's also not part of .NET but a generated COM interop shim to make the Excel interface callable from .NET.
I first saw this "hardcoded" varargs in Scala e.g. <a href="https://www.scala-lang.org/api/2.12.2/scala/Tuple22.html" rel="nofollow">https://www.scala-lang.org/api/2.12.2/scala/Tuple22.html</a> (replace 22 to 1-21). I guess it's platform (JVM) limitation? Newer Java also has something like this, but I can't remember which class.
"Why not just pass an array of arguments?"<p>Speed and convenience, I'd imagine? IIRC, arrays are marshalled as SAFEARRAYs in COM and those things are quite heavy-weight, you'd <i>really</i> rather call a 31-parameter function and pass it 27 NULLs in places of extraneous parameters.
Well, not sure why that's implemented as is, interop is some old technology and there are quirks or whatever. But .NET provides convenience methods/delegates, like typed Action<>[1] (or Func<>) with 16 arguments, so you don't have to explicitly define delegate yourself:
[1] <a href="https://docs.microsoft.com/en-us/dotnet/api/system.action-16?view=net-6.0" rel="nofollow">https://docs.microsoft.com/en-us/dotnet/api/system.action-16...</a><p>Today as of C# 4 you can for example have optional arguments. Not sure if this applies to this method which surely predates C#4.
PostgreSQL used to have two different APIs for internal/C language SQL functions, with the older one implemented in more or less this manner, but with distinct types for each argument count. The actual function call was then implemented as giant switch on number of arguments which called function pointer with progressively more Datum-typed arguments.<p>It got deprecated sometime around 8.0 and today it is not even supported (the giant switch got replaced by error message).
Reminds me of IFn from Clojure<p><a href="https://clojure.github.io/clojure/javadoc/clojure/lang/IFn.html" rel="nofollow">https://clojure.github.io/clojure/javadoc/clojure/lang/IFn.h...</a>
Somewhat related, one of my favorites from "Be Developer's Guide"[0]:<p><pre><code> is_computer_on_fire()
double is_computer_on_fire(void)
</code></pre>
Returns the temperature of the motherboard if the computer is currently on fire. Smoldering doesn't count. If the computer isn't on fire, the function returns some other value.<p>---<p>Though of course, the Microsoft engineer[ing committee] was entirely serious when they wrote the OP's function signature, while I imagine the Be engineer having a laugh while adding it to the SDK and then getting it into the official docs in print.<p>0. <a href="https://www.google.com/books/edition/Be_Developer_s_Guide/WoQ_AQAAIAAJ?hl=en&gbpv=1&bsq=be%20developers%20guide%20fire" rel="nofollow">https://www.google.com/books/edition/Be_Developer_s_Guide/Wo...</a>
Why wouldn't the just use the params [0] keyword for stuff like this?<p>[0]: <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/params" rel="nofollow">https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...</a>
Clojure has to do the same thing to interface with Java: <a href="https://clojure.github.io/clojure/javadoc/clojure/lang/IFn.html" rel="nofollow">https://clojure.github.io/clojure/javadoc/clojure/lang/IFn.h...</a>
Clearly you haven't heard of HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor<p><a href="http://dev.eclipse.org/viewcvs/index.cgi/org.aspectj/modules/weaver/src/org/aspectj/weaver/patterns/HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor.java?revision=1.1&root=Tools_Project" rel="nofollow">http://dev.eclipse.org/viewcvs/index.cgi/org.aspectj/modules...</a>
I check you, Rust static-size arrays that implement common traits... as long as they're no more than 32 elements long.<p>Yes, this bit me hard on first Rust-based project, to the point of abandonment. (A list that grow and shrink is <i>absolutely not the same thing</i>).
I see your function with many parameters and I raise you this constant: CNLabelContactRelationYoungerCousinMothersSiblingsDaughterOrFathersSistersDaughter<p><a href="https://developer.apple.com/documentation/contacts/cnlabelcontactrelationyoungercousinmotherssiblingsdaughterorfatherssistersdaughter" rel="nofollow">https://developer.apple.com/documentation/contacts/cnlabelco...</a>
Whatever it takes to make things work! =)<p>I guess stdarg.h like functionality would have been good for C#. Maybe some clean code purist argued against it because it is bad practice or something.
This is exactly why I dropped using C# and wend back to Java. Documentation on Microsoft products is really bad sometimes.<p>EDIT: Thanks for the downvotes. I am a professional software engineer for hire and in each company this is EXACTLY the issue: documentation. You want me to help you build software? Fine: give me your documentation. Complain about the fact that it takes 2 months to properly understand your software and business rules? Improve your documentation.