Hacker News new | past | comments | ask | show | jobs | submit login
_Application.Run(Object, Object, Object, Object, Object, Object, Object, Object (microsoft.com)
306 points by jamespwilliams on Jan 10, 2022 | hide | past | favorite | 208 comments



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.


"Any number of arguments", as long as that number is <= 30. But I hope that's enough for most use cases...


The developer ergonomics make more sense when you look at this from the VB side of things (positional or named arguments with everything optional), it's just the interop that is messy.


cough Scala 2 tuples cough


Also you can refer to a macro from another assembly that is not referenced by your assembly (you couldn't reference an xla addin from an ExcelDna .net addin for instance).


>Object, Object, Object, Object, Object, Object, Object, Object

Cmd+F, badger (Not found).

Cmd+F, mushroom (Not found).

https://www.youtube.com/watch?v=EIyixC9NsLI (video sfw, comments may be the usual YouTube battleground)


Buffalo Buffalo Buffalo Buffalo Buffalo Buffalo


This was my first thought. The c# version of the Buffalo Buffalo sentence.


Missing 2 buffalos.


I first saw this "hardcoded" varargs in Scala e.g. https://www.scala-lang.org/api/2.12.2/scala/Tuple22.html (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.


Another example is Java's java.util.Map.of. It's a convenient method to construct a map in a single statement.

https://docs.oracle.com/en/java/javase/11/docs/api/java.base...


This kind of function overload is present everywhere in the Java collection framework (and probably other libraries). It is a performance optimization (variadic arguments in Java require creating an array), and variadiac overloads also exist (Map.of needs a list of Map.Entry for type safety) for creating collections of any size.

https://docs.oracle.com/en/java/javase/11/docs/api/java.base...


Do note that the created map is immutable. However, you could pass the created map to the constructor HashMap (or another type) to obtain a mutable copy of the Map created using Map.of


It doesn't have the equivalent of variadic templates, which means you can't have something like std::tuple unless you either codegen it or make it not type-safe.

I did the exact same thing in Java for an internal library in order to provide type-safe Unit, Singleton<T1>, Pair<T1, T2>, etc.


I don't think I have seen classes with many parameters to avoid varargs in Java, however I have certainly seen classes with dozens of Type Parameters, I believe some form of code generation was responsible.

Can't for the life of me find that class again.


SLF4J Loggers define up to two arguments for precisely this purpose:

https://www.slf4j.org/apidocs/org/slf4j/Logger.html#error(ja......)

> This form avoids superfluous string concatenation when the logger is disabled for the ERROR level. However, this variant incurs the hidden (and relatively small) cost of creating an Object[] before invoking the method, even if this logger is disabled for ERROR. The variants taking one and two arguments exist solely in order to avoid this hidden cost.


Look at Set.of and Map.of. Lots of overloads to avoid allocating the vararg array.


It’s to prevent allocating the array for varargs.


Yes. This used to be one of those things that made a significant difference but probably doesn't matter any more. I say "probably" because I haven't seen any code like this that wasn't spat out from a generator in a long time


"Why not just pass an array of arguments?"

Speed and convenience, I'd imagine? IIRC, arrays are marshalled as SAFEARRAYs in COM and those things are quite heavy-weight, you'd really rather call a 31-parameter function and pass it 27 NULLs in places of extraneous parameters.


Only if using safe-for-scripting/Ole Automation types/interfaces in your IDL. Otherwise, it's fully possible to pass C-style arrays in COM.


Excel is out-of-proc so it relies heavily on marshaling. It's either that or custom marshaling. Also it's the same interface as is used internally in the application with VBA scripting.


Which is the case here, => "Microsoft.Office.Interop.Excel".


I feel like the "Who wrote this shit?" article and this one should be linked together ...


This is not bad code


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] https://docs.microsoft.com/en-us/dotnet/api/system.action-16...

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.


The args for this method are all optional and it would be exposed to C# through a COM API so I’d expect C# to treat them as such.


This specific use case was in fact one of the motivations for introducing optional arguments back in C# 4.


And if you need more than 16 arguments, as of C# 10 the compiler will synthesize an anonymous delegate type in some cases:

https://github.com/dotnet/csharplang/blob/main/proposals/csh...


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.

It got deprecated sometime around 8.0 and today it is not even supported (the giant switch got replaced by error message).


This reminded me of writing a `is_set_cover_possible` PL/Python function for Postgres. I wanted to take an arbitrary number of arrays. Apparently it's not possible so I just had to overload the function and hope that I would never need to check more than n arrays...

https://stackoverflow.com/questions/56623975/pl-python3-with...


I suspect that the giant switch was exactly the reason why it was not originally possible.


"Thirty arguments should be enough for everybody"


I would have stopped with far fewer arguments.

When did you last call a function with more than 10 arguments, let alone 30?

Now I'm tempted to go through my code to find the max number of arguments I've used.


Right, but you're calling into a huge dynamically typed external app, and that may have entirely different conventions for reasons that make sense in that app (here excel).

Normally, 30 is crazy. But in excel? Who knows...

Also, too many isn't a problem, they're optional, so in practice you'll be treating this as a varargs; there's not much cost to having a few more args. I haven't used this function, but I suspect I'd rarely call in directly anyhow, instead making sane wrappers for various apis you actually care about which in turn call this internally, making the direct call details even less relevant.


I wouldn't, but if I'm passing something to an external command line tool with many options like ffmpeg, it might be over 10.

Anyone regularly calling a function with actually 10+ parameters is calling for a refactor though.


It depends on your domain. Some functions are effectively entire programs which can have huge amounts of configuration required. Many R packages expose a single function that can easily take that number of arguments


My maximum is 13, a function that creates an object with 13 properties.


I have definitely seen more than 10 arguments. Usually these are the god functions that no one wants to touch and keep adding one too many parameters as it is updated to support new features.


My heuristic: If you have 5 or more arguments, you should use a config object.


My heuristic is to not be dogmatic like that. A constructor for a triangle class may reasonably want to take 6 arguments (3 x- and 3 y-coordinates). In other cases, even four arguments might be better as a config object if those 4 are all very rarely used.


How many do you want?



Rust has something similar, where some libraries implement on all the different tuples (X1, X2), (X1, X2, X3), (X1, X2, X3, X4), etc.


So has Haskell. I've also seen it in other languages as well.

I guess in Rust and Haskell they are not params of type "Object". Those languages try to maintain type safety where every they can.


Perhaps Haskell could have defined tuples inductively. There are HList libraries that essentially offer this functionality though.


Ah yes, but they're missing a trick! There's a library for that: https://hackage.haskell.org/package/product-profunctors


Heh:

https://hackage.haskell.org/package/product-profunctors-0.11...

> cl_map :: Default Zipper a b => (b -> r) -> a -> [r]

> A challenge from a Clojurist on Hacker News (https://news.ycombinator.com/item?id=23939350)

The referenced comment:

> I think the general feeling is that there are some code patterns that are safe and easy to do with dynamic typing, but impossible with simple type systems or more complex with more advanced type system.

> An example would be Common Lisp's `map` function [0] (it takes a number of sequences and a function that has as many parameters as there are sequences). It would be hard to come up with a type for this in Java, and it would be a pretty complicated type in Haskell.


Somewhat related, one of my favorites from "Be Developer's Guide"[0]:

  is_computer_on_fire()

    double is_computer_on_fire(void)
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.

---

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.

0. https://www.google.com/books/edition/Be_Developer_s_Guide/Wo...


Poor naming to have a function named like a predicate return a double. Should have been computer_fire_temperature() or something.


Haha yes, it was the 90s and all sorts of crazy things were gotten away with back then.


computerTemperatureWhenFire :: IO (Maybe Double)


...whereas in PHP there’s a setting in php.ini with a Hebrew name that will cause the function to spin-lock, pegging your CPU to 100% until it does catch fire, so that you can be sure it’ll always return a value. And it defaults to true.


Why wouldn't the just use the params [0] keyword for stuff like this?

[0]: https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...


Because this is an OLE 2.0 library for Office automation.


My humble guess is that it didn't exist when this was designed?


This looks like the interop libraries auto generated off the Office OLE Automation interfaces. SafeArrays should have existed back then. I imagine this was used instead for perceived developer friendliness vs forcing developers to box up and create a Safe Array to marshall in (more boilerplate).


Don't think it works in this case. In general why there are so many overloads in C# with parameters like arg0, arg1, arg2 and so on is because of the poor performance of the params solution for value types.


Clojure has to do the same thing to interface with Java: https://clojure.github.io/clojure/javadoc/clojure/lang/IFn.h...


I don't know that it "has to", as the last overload has variadic arguments. (Caution, I'm not a Java expert).

This is likely for JIT performance, with virtual method lookup. C# does the same thing with string.Format - https://docs.microsoft.com/en-us/dotnet/api/system.string.fo...


Are you looking at the "applyTo" method? I'm not seeing a variadic overload of "invoke", but I'm also not a Java or JVM person. I'm wondering if I'm overlooking something.


"If you have a procedure with ten parameters, you probably missed some." -- Alan Perlis


Why did they pick 30 optional arguments? I assume they just picked a number of arguments way bigger than you would actually require in the real world.


I think that’s the max number of arguments in VBA.


Interesting, that's my memory too, but a quick test reveals it to be 60 now. It's even documented: https://docs.microsoft.com/en-us/office/vba/language/referen...

Wonder if they changed it at some point, or if I'm just misremembering.


I think this (and similar) Office interop method signatures were the reason they created optional parameters in C#.



I'm glad they provided documentation for all thirty parameters.


run object run!

I can see how this is not beautifull but works. Especially when its probably been there for 20 years already :D


Clearly you haven't heard of HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor

http://dev.eclipse.org/viewcvs/index.cgi/org.aspectj/modules...


Link seems dead for over a decade; archive: https://web.archive.org/web/20081207180615/http://dev.eclips...


returns 404 file not found


Why not just App.run(Object &Args?) ?


I check you, Rust static-size arrays that implement common traits... as long as they're no more than 32 elements long.

Yes, this bit me hard on first Rust-based project, to the point of abandonment. (A list that grow and shrink is absolutely not the same thing).


That hasn't been the case (except for Default) for a few months.


Another day, another example for why argument labels and variadics are really nice to have ;)


EVen in .net that HAS variadics, there are no stack allocated variadics (yet) so you'll often see 8 overloads with foo(T arg1) foo (T arg1, T arg2) foo(T arg1, T arg2, T arg3) and so on up to foo(params T[] args) because you want to avoid the overhead of actully allocating an array only to pass to one method, if you can. You'd think this kind of thing could be unfolded at compile time instead of requiring manual overloads.


Actually it’s not. This is to call any other macro (function), the first argument is the name of the macro as a string, and the other arguments are the parameters that will be provided to that macro, which can be of any type and have any name. So it kinds of need to be that way.


Right, so this would be something like Application.Run(macro: Object, arguments: Object...) which would clean it up nicely.


That’s what the definition a bit further down the page says. The header of the page seems to be the function signature so it doesn’t contain any name.


In languages with argument labels, they are part of the signature and show up in the call site.


C# does have optional named parameters (see link below). But it is little help here as this is an old COM library for Excel. The documentation says named parameters are not supported for this method, which is a COM interop limitation but not a limitation of the C# language.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-g...


hmmm - I love strict static typing. Fewer runtime errors and great tool support.


...and that's how _Application.Run.apply was invented


I would really like to hear the story told by a product manager about this... and learn about the discussions with the engineers on this :)


You think a product manager was in any way involved with a function signature. I'm fairly certain this didn't come up in more detail than a requirement: "We need to add a way to call a macro...". And the story as told by the PM would be "...and so the engineers added a way".

I've worked with a bunch of PMs on technical products, APIs, etc. and I've rarely met anyone discussing that level of detail or willing or able to make such a decision.

The engineers chose a way that worked and it's likely the best way supported at the time, given the other comments I've read here on HN.


Joel Spolsky was the program manager (true, not product manager) when VBA was added to Excel. He talks about it on his blog.

"As a program manager at Microsoft, I designed the Visual Basic (VBA) strategy for Excel and completely speced out, to the smallest detail, how VBA should be implemented in Excel."

https://www.joelonsoftware.com/2000/10/04/painless-functiona...


Doesn't the language supports variadic functions?


C# does. But does Excel? No surprise an interop shim would use an API that matches Excel rather than the best available.


Where do I even start to begin to understand this?


At Object


Working without variadic templates is painful.


Rust does the same thing with tuples.


The ultimate abstraction!


wow even solidity is better than this, and thats a super low bar! just pass an array


Sure. Just implement that retrospectively for OLE 2.0.


I see your function with many parameters and I raise you this constant: CNLabelContactRelationYoungerCousinMothersSiblingsDaughterOrFathersSistersDaughter

https://developer.apple.com/documentation/contacts/cnlabelco...


This video summarizes the family relationships that these variables represent: https://www.youtube.com/watch?v=nCFRoILS1jY

People really do use these relation names instead of given name. Everyone in the family using different names, which is confusing to watch as an outsider as you can't learn their given names. It would be like watching everyone else in a family refer to a single person as "sister", "cousin", "niece", "aunt" etc. No-one uses their given name so you as an outsider aren't sure what to call them.


That’s a specific relationship with its own dedicated name in Chinese


For other items that native English speakers may not know - I believe in some Indian languages there are different nouns for your uncle and aunt, depending if they are on your father's or mother's side.


I like the Swedish variant of this. It's basically describing the relationsship in terms of closes family ties, so maternal grandfather is "morfar" ie "mother father". Same principle applies to a bunch of relationships:

farmor - father's mother

farfar - father's father

faster - father's sister (abbreviated from "far syster")

moster - mother's sistem (abbreviated)

farbror - father's brother

I like to extend the basic set of these to older generations, so instead of "my mormor's father" it'd be "mormorfar". Very practical!


Its interesting how different languages have evolved, so Inuit have many words for snow because this highlights area's of concern or importance for them. So the fact these language differentiations exist in Indian and Chinese language, highlights an area of concern or importance for them.

In Iceland, surnames use the fathers firstname and sson for son and dotir for daughter, to highlight the relationship in an otherwise small community. Whether that cultural habit is to reduce the incidence of inbreeding I've yet to find out, but it makes me wonder. History and culture gives away a lot of metadata.


It's not at all clear it makes it easier. My great-great grandfathers children and the children of his brother have different last names. That's before dealing with the hassle of married names vs. maiden names for the women.

Most of my family is in Norway and Sweden, and used pretty much the same method as Iceland, except to throw an extra wrench in, a lot of the time people would either use the name of the farm they were born on in addition or or instead of the name derived from their father. Since that could often include extended family, and different owners over time, there might be a proliferation of people with the same last name as you with no close relationship, while someone with a completely different name might be your first cousin.

My last name only exists because one of my ancestors got tired of the name confusion and renamed his farm (changing one letter) because the local area were full of people with the same last name on farms with prefixes like little/large/upper/lower to separate them all, most of whom are not closely related to us due to purchases (the exact same change has happened two different places in Norway; as a result about 50% of people globally with the same last name as me are relatively closely related to me - the other roughly half we've not found a connection point to, but of course one will exist far enough back).


Historically, I believe this is true for all Norse cultures. The most common surnames in Sweden (like Andersson) are afaik based on the most common given names when surnames were changed to be static in families, which was a gradual process a few hundred years ago.


It wasn't "finished" until much more recently than a few hundred years ago.

My great grandfather Søren Kristian Magnussen was born in 1890, and he got his fathers last name. His father, August Magnussen was born Magnusson in 1842 to a Magnus Andersson near Bullaren in Sweden (ignoring the mothers here only because they had no impact on the last names). August's brother Johan Alfred Magnusson had (at least) three children who were named Johansson / Johansdotter born between 1885-1890. So even that late some children's last names were still derived from their fathers first names.

It makes genealogy both easier and harder - on one hand apart from during and after the transition period you get the fathers first name "for free" (most of the time, except when they complicate things by using the name of a farm instead of a last name), on the other hand it makes searches for the transition period a real mess (as if the poor hand writing of everyone involved in record-keeping isn't bad enough).


> In Iceland, surnames use the fathers firstname and sson for son and dotir for daughter, to highlight the relationship in an otherwise small community.

The same happens in most Slavic ("Vladimir Vladimirovich Putin" is basically "Vladimir son of Vladimir Putin"; a hypothetical sister could have been "Ekaterina Vladimirova Putina", Ekaterina daughter of Vladimir Putin) and some Turkic cultures (Nursultan Abishuly Nazarbayev is the son of Abish Nazarbayev), so the theory that this is related to tight nit communities on a small island seems highly unlikely.


I didnt know how the naming system works in other countries, I only know about Iceland and UK, but I still suspect the naming exists to highlight relationships. The point I'm trying to make is that when the naming system was introduced or adhered to in an area on this planet, I wonder if they knew about the problems of inbreeding, you see here in the UK, with livestock, you typically have a one or two studs and the rest of females, so there is an element of inbreeding or deviation towards it. Pig farmers will have two or three bores fertilizing the sows, cows will get a bull and roosters are also limited to one for a brood.

So did/does some cultural naming system highlight a lack of inbreeding knowledge or not when considering when it was introduced?


“ Whether that cultural habit is to reduce the incidence of inbreeding I've yet to find out, but it makes me wonder.”

That’s racist. “The only way these people are going to be able to stop fucking their cousins as if they come up with a naming system that makes it extremely clear who is related to who.” There are probably other explanations other than being inbred as to why they do this. Like how some people go by Junior or Senior. Do you think that’s to prevent inbreeding also?


Knowing who is related too closely to you can be a problem on a small island, the comment was possibly referencing the Icelandic dating-app that tracks if you share a grandparent with someone you meet in a bar[1]; a feature the app itself calls a "Sifjaspellsspillir", or "Incest Spoiler".

Interestingly the article mentions that this is a problem precicely because of the Icelandic naming scheme:

> Neither patronymic or matronymic, instead each person's father's first name becomes the child's last name. Each new generation has a completely different name to the name of the generation that preceded it. Cousins, aunts, uncles, nieces, nephews -- all could have very different names.

[1] https://www.wired.co.uk/article/iceland-incest-app


Ooh, this is just like Lisp’s CADR being a composition of CAR and CDR!


Many other languages do. I think all Chinese languages do, but you don't need to go that far. Even German/Dutch/Frisian/Swiss do have it, although nowadays few use them and many people don't even know. (Father's siblings are Onkel/Tante cognate to uncle/auntie, but Mother's siblings are Oheim/Ohm/Öhi if male and Muhme/Muoike if female.)


> I believe in some Indian languages there are different nouns for your uncle and aunt, depending if they are on your father's or mother's side.

Not only that, but in some cases depending on their (the uncle and your father) relative age. I'm learning Hindi, so for example paternal uncle older than your father is your taaya (ताया, or taauu ताऊ) but younger than your father is your chaacha (चाचा).


This is also the same in Arabic. There are separate words for paternal/maternal aunt/uncle, and by extension your cousins who are "son/daughter of paternal/maternal aunt/uncle".


And, for paternal uncles, different words to indicate if they are older or younger than your father.


What is this relationship? And what does "younger" mean here - younger than the contact?


I've seen this explained before; from memory, it's a type of cousin, with specifiers:

Chinese has distinct words for relatives of the same generation (siblings, cousins) who are older or younger than oneself. Like "big brother" and "little brother" in English, but you always include the big/little part. "Younger" specifies that this cousin is younger than the person whose contacts book this is.

Female - Chinese has separate words for male and female cousins

The rest of the word salad specifies a relationship that is approximated by answering the question "is her (maiden) surname the same as my (maiden) surname?" in the negative — either she is a daugher of one of my mother's siblings, and doesn't share my surname because I have my father's surname, or she is my father's sister's daugher, and thus has her father's surname, which again is not the same as mine.


I'm guessing this is 表妹.

In English, your male siblings are "brothers", and female siblings are "sisters", regardless of age.

In Chinese, we differentiate between younger and elder siblings. Your elder brother is 哥哥, younger brother is 弟弟; elder sister is 姐姐/姊姊, and younger sister is 妹妹.


It would seem reasonable to me to use the latinized form of the Chinese word as part of the identifier instead of the awful descriptive identifier.


I honestly don't know if I would prefer CNLabelContactRelationYoungerCousinMothersSiblingsDaughterOrFathersSistersDaughter or CNLabelContactRelationBiǎoMèi (is unicode even allowed?). And I probably butchered that romanization and upset half the internet in the process.


If unicode is allowed, you can also use the Chinese characters


Then about 80% of the world wouldn't know how to pronounce it.

A quick test in google would suggest that CNLabelContactRelationBiaoMei doesn't introduce too much ambiguity (first result for Biao Mei is still about the correct term), so even without unicode it might be fine.


It's not specific to one Chinese Language or even just Chinese.


Surely it has a more generic name, then.


think about what you’ve just said


If you’re suggesting the current identifier is already latinised, it’s not, it’s translated.


I've basically just said that, e.g., instead of the identifier EmployeeTheNumberThatIdentifiesATupleInARelation, you should really be using the identifier EmployeePrimaryKey. That is, you usually refer to things using the name of the respective concept, not by describing what the thing's concept is every time you're trying to refer to the thing. It's called "coining a term". Or, in programming, abstraction (as per SICP, that is giving a name to some compound construct so as not to be forced to repeat it endlessly).


I would like you to figure out what that would be and post it here.


Also don’t chinese family relationships distinguish beetween maternal and paternal-side relationships? E.g. a cousin on your father’s side is called / qualified / described differently than a cousin on your mother’s side?


correct, father side is prefixed with 堂 mother side is prefixed with 表

堂哥 male cousin older than me 堂弟 male cousin younger than me 堂姐 female cousin older than me 堂妹 female cousin younger than me

表哥 male cousin older than me 表弟 male cousin younger than me 表姐 female cousin older than me 表妹 female cousin younger than me


As I understand, only children of father's brothers can be prefixed with 堂, because they have the same last name and are traditionally considered to be in the same house. All others, including children of father's sisters, are all prefixed with 表.


Isn't that "Kleincousin" in German? "Younger" could certainly match the "Klein" part. That would be the daughter of your cousins, so there's surely a male variant too.


I'm German and I never heard the term "Kleincousin". According to Wikipedia [0] it seems to be used regionally to refer to 2nd degree cousins (which I would call "Großcousin").

Anyway, "Kleincousin" and "Großcousin" don't imply the age of the cousin, but a degree of relationship (with regional differences to what is actually meant).

To refer to a younger cousin, I would just say "jüngerer Cousin". "kleiner Cousin" may be possible too (like "kleiner Bruder" for a younger Brother), but it sounds a bit like childs talk and it may not be immediately clear to everyone what is meant.

[0] https://de.wikipedia.org/wiki/Verwandtschaftsbeziehung#Cousi...


表妹(mother's side) or 堂妹(father's side)


Yes, I believe these relationships also have their own names in Korean, if not lifted directly from Chinese most likely.


Oh yeah, what about this Java class?

HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor

It inherits the following methods from class org.aspectj.weaver.patterns.AbstractPatternNodeVisitor: visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit

https://www.javadoc.io/doc/org.aspectj/aspectjweaver/1.8.10/...


I like its boolean method wellHasItThen(). It pretty much describes the mood of the developer at the time of writing.


A more brief, but less objective, way of saying this is "young female cousin via female parent". As others have pointed out, the Chinese care to track this relationship.


It's about being younger than you, not merely being young.


And probably "via a female parent" as your father's sister's daughter isn't through your female parent.


> A more brief, but less objective, way of saying this is

It really isn't complex.

妹 - female, same generation, younger than you.

表 - cousin outside your family.


"cousin outside your family" is an oxymoron in most of the western world. getting this concept accross is why the constant is so awkwardly worded.


> "cousin outside your family" is an oxymoron in most of the western world

It's a tangent, but I would actually argue that in the Western world, all cousins are outside your family and the concept of a cousin belonging to the same family as you is the unthinkable one.


In the Netherlands at least, we use "familie" to refer to the extended family. To talk about the immediate family or one's household, we would use "gezin" (Although I think some parts of the Netherlands may use "familie" for the nuclear family as well? Not where I live, though.)

We don't generally distinguish between matrilineally and patrilineally related family, which is what the "cousin outside the family" was originally about.


Using one word for your family and an unrelated word for your other relatives, including your cousins, doesn't make it sound like your cousins are part of your family. That's a sharper distinction than is drawn in English.

This isn't a question of the pronunciation of the word you use to refer to remote relatives. It's a question of the social relationships that exist between you and your relatives.


Imagine the abstract bean proxy factory required to create an instance of that!


I posted that on HN few months ago and it broke the layout of HN:

https://news.ycombinator.com/item?id=28712667


Past discussions:

CNLabelContactRelationYoungerCousinMothersSiblingsDaughterOrFathersSistersDaught - https://news.ycombinator.com/item?id=28712667 - Sept 2021 (132 comments)

CNLabelContactRelation&NegativeMediumSpace;YoungerCousin&NegativeMediumSpace;MothersSiblingsDaughter&NegativeMediumSpace;OrFathersSistersDaughter - https://news.ycombinator.com/item?id=20341855 - July 2019 (176 comments)


Do they have one for father's brother's nephew's cousin's former roommate?


Oh wow it’s even longer. For some reason on iOS mobile it cuts off your text here.


Inevitably, when I review code like that, I immediately suspect the person who wrote it is missing some fundamental programming concept.

I had developer write something like that once and I learned she does not know how to write loops.


I thought this was a Spaceballs reference.

https://www.youtube.com/watch?v=riqXhieWU3M


FireWomenAndDangerousThingsNounClass


I thought this was a Spaceballs reference.


this is really interesting lol


anti-pattern detected...


Only one?


Sounds like something probably inappropriate X-]


If your class is called FooOrBar then you are bad at naming things.


Or maybe it’s worth taking a couple seconds to understand the problem domain before judging someone else’s code.


Regardless of the domain: classes with And or Or in them are at the very least a codesmell. Because the name even implies it does more than one thing (SRP)


It's not a class, it's a variable. The Or is there because the same Chinese word refers to two possible relationships within a family tree. It doesn't do more than one thing, it represents more than one relationship. If the word 'Sibling' didn't exist, we could use 'BrotherOrSister' in its place.


Or it represents one real thing that has multiple purposes outside the code and so the code can't fix that.


True.

But I've honestly never encountered this. Not in a valid domain concept. Where "valid" means it is truly embedded in the domain: and not some historical artifact that has been carried along for far too long¹

I'd love to see what valid real-world use-cases there are for an "FooOrBar" or "BarAndFoo" domain concept.

-- ¹ Which is a conundrum, I know. If some legacy system or even legacy software was badly designed (or not designed at all, but just evolved over time) carries along its "design flaws", after so many generations or iterations, it becomes the domain concept itself.


You've caveated the "valid" answers out of existence. But here are some examples of or-ed concepts:

* parent or legal guardian (shows up on legal forms all the time)

* state or province (an English language political construct)

* DNS name or IP address

You could argue that "parent of legal guardian" is a legacy concept since it really just means "legal guardian", but it's literally written on legal forms, so it's a domain concept, except if you believe it shouldn't count because it's an anachronism.

You could argue that we don't need "state or province" since we can just say "region", but "region" doesn't mean "state or province" colloquially, and we have to be careful not to refer to Ontario as a state, so the distinction is important. Ironically, that distinction does not exist in Chinese, but it does in English.

"DNS name or IP address" absolutely are two different concepts, it just happens that URL's were specced to accept both as the "host" segment. So whether or not it counts as an example depends on whether you believe that the act of coining the term is also the act of erasing its status as an "or" relation. Alternatively, if you're implementing a web browser, that distinction absolutely does exist because you need to know not to try to resolve an IP address as a DNS name.


I agree about the first two. The legal one being the most strong.

WRT "state or province": I've modelled quite some GIS data and tend to follow abstractions laid by OSM here. Where "state" is very different from "province" because in many locales that is the case;

But maybe your model is purely Chinese and the OSM model -albeit being global- has a poor local fit.

The latter: nah. It's the one I know about most, and I'd say, depending on your use-case, "address", "host", "location", URI, URL, etc are a better name for what you are modeling than "DnsOrIpAddress". If only for the fact that this can be read as "DNS Address Or IP address" as well as "DNS, or IP-Address". It is truly a bad name in many situations.


Fair enough, but you've surely encountered those first two before.


> But I've honestly never encountered this

Boy do I have the perfect example for you then: https://developer.apple.com/documentation/contacts/cnlabelco...


and, as many people pointed out, the actual domain concept is in Mandarin, and a single word.

So a perfect example of the word "Or" that does not denote a logical disjunction but a translation-artifact. I thought it was obvious that it is not literally implied the letters O and R are never allowed after each-other in code. I mean: obviously having a class named OrGate in an electronics simulation is fine. As is OrParty in a system modeling Israelian politics.

This is about the word Or denoting that your class, value, type, variable, model etc, is One Or The Other.


Then I'm not really sure what your point is. People were talking about the specific domain mentioned, then you said "or" is code smell regardless of domain, then people pointed out why it's _not_ code smell in this domain, then you come back and say "of course it's not code smell in this domain, I was talking about something else".


My point is that if you have a class, or method, or variable that represents "one thing, or another thing" this is a poor abstraction. And that you can "reek" this smell quite clearly if your names contain "one Or the Other" or "One And The Other" the words "Or" or "And".

The example you gave is an artifact of a translation. It is not an indication that this class holds either a "YoungerCousinMothersSiblingsDaughter" class/type/value Or a "FathersSistersDaughter". First, because AFAICS these separate things don't exist. And second because of the first part of that name: `LabelContactRelation`, it being a label; not a return value.

You did pay attention to the part where I explained that this, naturally, is not literally so, did you?


Right, I think you missed my point. If the example being discussed by everyone in this thread does not apply to your point, why did you bring it up in the first place and cause this confusion? And why did you say "Regardless of domain" if that's obviously not true?


All code does more than one thing, and this is not what the SRP (Single Responsibility Principle) is about. The SRP says a module should not implement multiple independent business concerns.


What if it's an Either type / some kind of discriminated union? e.g.

type PersonOrError = P of Person | E of Error

It can be either or a Person or an Error


If it is an argument, it is certainly a design issue:

`response_serializer(PersonOrError: person_or_error)` is confusing, impossible to reason about easily, hard to test etc. It signals a way too tightly coupled API, for one. And it breaks the SRP, secondly.

Why not `response_serializer(Person: person, Error: error)` or `try_error(person).then(response_serializer(person))` or many other designs that do the same, but make it explicit where, when and why the distinction is made.

It is something you often see in e.g. Rails, though. And I consider it really poor and confusing API: an example of that dreaded "Rails Black Magick" where a method like `form_for()` can get literally hundreds of combinations of arguments and behaves entirely different according to what is being passed. In runtime. In production. With user-generated content and dynamic typing and all that.

If it is a return-type, there too: why not make it a tuple, or do like Rust: make it an `Option<Some, None>: user` or a `Result<Ok, Err>: user`, the typing now contains this "either/or" not the variable names;

And if it is a class, or even method: it is violating SRP.

Neither of the reasons are absolute. But they all signal that a better solution is possible (but maybe not practical given constraints). Which is fine: but acknowledging this design is lacking (and choosing to still use it) is IMO the correct path; telling yourself that the design is fine, is not.


> And if it is a class, or even method: it is violating SRP.

Not always! Somebody is going to have to discriminate on the argument, and if indeed the caller already knows what they're providing, there's no need to wrap it in an Either -- there should be individual methods for both variants. But if the caller doesn't know what it is yet, and the type represents a domain concept that happens to be a set of options, then there's no reason the caller has to busy itself with that knowledge. To the caller, this might be (actually or morally) an opaque type, and the callee may be where knowledge about it is centralized, and hence where discriminating on the variants ought to happen.

The single-responsibility principle is definitely something that always needs to be kept in mind, but it's not something that can be replaced with broad rules, either.

> If it is a return-type, there too: why not [...] do like Rust: make it an `Option<Some, None>: user` or a `Result<Ok, Err>: user`, the typing now contains this "either/or" not the variable names;

That's exactly what they did -- in the ML-like syntax they used, their `PersonOrError` is exactly `Either<Person, Err>`, but with the type arguments pre-instantiated.

    type PersonOrError1 =
      | P of Person 
      | E of Error

    type 'l 'r either =
      | Left of 'l
      | Right of r

    type PersonOrError2 = Person Error either


I agree about passing Either types as arguments, I wouldn't do this. Pattern matching solves this problem.

> If it is a return-type

As for making them return types, it forces you to match over them, you can have the compiler do exhaustive matching over the types it can be. If you have a tuple of (int, string), you could store an int and a string. With Either types, it has to be one OR the other, it can never be both.

Like I said, you can pattern match over this depending on what the type contains. It also allows nice binding and failing out the chain early. e.g. something like in a C style syntax:

    public Either<Error, int> M()
    {
       "In M".Print();
       return 6;
    }

    public Either<Error, string> M2(int y)
    { 
       $"In M2 {y}".Print();
       return $"{++y}";
    }

    public Either<Error, string> M3(string y) 
    {
       $"In M3 {y}".Print();
       return $"Result {y}";
    }

    public void ShowResult(string y) => y.Print();
    public void DisplayError(Error error) => error.Message.Print();

    M().Then(M2)
       .Then(M3)
       .Match(left:  DisplayError,
              right: ShowResult);
 
So, the functions that operate on the Either types only ever take the right type of the Either. If say M2 returned an Error, M3 would never be called and you shortcut to the error handler.

The match forces you to explicitly handle if it's an error or not.

I like this pattern, it can be concise and expressive when used in a context where it's applicable.

> And if it is a class, or even method: it is violating SRP.

I disagree, the Person class is just a Person (and nothing else), the Error class is an Error and nothing else. The Either class is generic and is a way to hold Either of multiple types (but only one at any time).

> make it an `Option<Some, None>:

I like Rusts option type, but the problem is the None state doesn't collect information, but I think it's certainly a nicer alternative to null. Again you can compile time enforce pattern matching to ensure you handle both states.

> Result<Ok, Err>: user`

Assuming Result can only ever be OK or Err, this is basically an Either type!


> Assuming Result can only ever be OK or Err, this is basically an Either type

Yes. It is the same concept.

SRP is rather vague, and interpreted differently depending on when and where to apply it (SRP for microservices is very different from SRP for a method).

But for the Either, or the Result, it applies perfectly. Because this thing does only one thing: it discrimates between this or that: it leaves what this and that do, are, mean etc to this and to that.

I was trying to put forward examples where the code does both this discrimination and applies the resulting meaning from it. In dynamically typed languages a bigger problem than in many others, where e.g. "null" or "some object of type X" or "a string with the error message" are far too common as return values.


Not necessarily. If your code is in English, and your category does not exist in English (like this Chinese word described here), then I do not see how to do better than this salad.

How would you have named this class?


One option (not necessarily a better one) is to use standard notation for kin relationships that basically show how to traverse the tree starting from ego: https://www.kintip.net/index.php?option=com_content&view=art...


I don’t see how it would help to dispose of “or”. It would just make it less readable.


Family trees are not trees but graphs.


acyclic graphs, hopefully


See the German TV show Dark for in interesting take on what could happen if they somehow became cyclic.



Seconded! Quite bizzare it was, a fun bingeing session a few years back.


Well, family graphs including relationships by marriage and adoption are not in general acyclic.


While wordy, the class name is representing a real relationship that users care about. The developer could have borrowed the underlying word from e.g. Mandarin, but then it would be weird to use that when set to Cantonese.


It's not a class, it's a variable.

If another language uses the same word for their aunt or uncle, a decent way to represent that in English is `AuntOrUncle`.

If the word 'Sibling' didn't exist, `BrotherOrSister` could be used instead.


Not much you can do when you have a semantic gap in your language.


Object arguments go brrrrr


Buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo.


Whatever it takes to make things work! =)

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.


There is, it's called "params" [0], and it has been there since C# 1.0. But the link is about the Excel's interop, and that thing originally dates back to, I don't know, 1993 or somewhen around that time? It never was dropped/redesigned due to backward compatibility, so the latter improvements were simply bolted on top of it.

[0] https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...


Oh didn't know that. And here I am trying to be smug. Seems to only take the same type though? However in this case it would work since they are all Object.


That’s not C#, this is the Excel COM API reference. Param arrays exist in VBA, but I don’t know if they do for COM.


Do you mean passing params as an array? It does exist in C# https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...


20 args function? I could be that purist in here :) idk what to say apart of hahahahahahahahahaha... Well, another gem from microshit :D


This is exactly why I dropped using C# and wend back to Java. Documentation on Microsoft products is really bad sometimes.

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.


This is simply describing a method in the Excel object library, which is not implemented in C#. The method pre-dates C# by many years.

FWIW the place to look for documentation of Application.Run is here: https://docs.microsoft.com/en-us/office/vba/api/excel.applic...


I think that the complaint was about MS technical documentation which is justified IMHO.

MS technical documentation has always been more concerned with quantity over quality.


This has nothing to do with C#. The javadoc for this exact problem would have been identical


I agree that the DCOM interface by IBM (20 years ago?) was just as bad... but if the source does not provide any documentation how can you be more clearer if you open it up in another language?


Microsoft probably has the best doc I have every seen compared to Apple…


Around ten years ago I would have agreed, MSDN was fairly nice, pretty comprehensive even if a bit full of seemingly autogenerated descriptions like "FrobnicateBar: Frobnicates the bar and return result" at the edges. Nowadays? Not so much.


With MSDN docs the older the doc the better it is. Pick something from the early days of win32 and it is a 10 page doc, very well done. Pick something they made up last month and you usually get very basic things. It has been that way for a long time. I remember the orig .NET docs were terrible to use. They have improved decently over the years. I can not prove it but I suspect the docs are only improved when a support case necessitates it.


It is an internal function though. It is just marked as "reserved for internal use".


The public version is identical

https://docs.microsoft.com/en-us/office/vba/api/Excel.Applic...

The args have to be object/variants, as it is the values for the sub that will be called and they can have any type. You would use generics today but keep in mind this is 1990s API.


That's even worse...




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: