Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
fishmech
Jul 16, 2006

by VideoGames
Salad Prong
Aren't all of the Unity weirdnesses with C#/.net things down to the fact that it relied on old Mono implementations when support was added to the original engine?

Of course, they should have loving fixed that over the 10+ years and several major versions since that happened, which has included things like deprecating their "Boo" scripting thing and "UnityScript" modified ECMAscript, and I think some other stuff.

Adbot
ADBOT LOVES YOU

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

redleader posted:

What the gently caress? How? Why? How? Why?

I'm actually in awe - this is quite possibly the most perfect coding horror. I don't think this is even possible without loving up the runtime itself.

I guess Unity is just going to have to totally give up on the nullable reference type thing coming in C#8?


This is absolutely a true horror. Silently stealing the name of .NET's most fundamental type and then tacking on some loving absurd behavior is entirely Unity's fault. I'm surprised the compiler didn't complain about ambiguous class names. What happens if you do new object() vs new Object()?

The fun thing is that this isn't actually the horror you think it is. You can't actually create a new UnityEngine.Object, since it's normally backed by a C++ object. They patched the == operator so that any C# Unity Object without an underlying C++ Object to compare equal to null: https://blogs.unity3d.com/2014/05/16/custom-operator-should-we-keep-it/

We just hit this earlier this week at work.

vOv
Feb 8, 2014

Soricidus posted:

The tweet talks about MacBooks not iPhones. Does macOS proper do autocorrect now? Because that would be pretty stupid, as the only reason autocorrect is necessary in the first place is that touchscreen keyboards are so ridiculously inaccurate. Text entered with an actual physical keyboard should not be altered without user intervention.

This link suggests that autocorrect has been on by default since 10.11, and enabling it on my computer I can confirm that 'duloxetine' gets corrected to 'fluoxetine'. It also has an 'add period with double-space' thing, which makes even less sense to me since it's not like it's particularly hard to hit the period on a proper keyboard. Maybe it's for really slow/bad typists?

vOv fucked around with this message at 05:15 on Dec 25, 2017

Steve French
Sep 8, 2003

As others have pointed out, part of the problem is that autocorrect in a desktop operating system where people are presumably operating with real loving keyboards is real dumb; the other half is that even if you are going to provide autocorrect functionality, it should be made really loving obvious when the machine has taken it upon itself to change what you wrote.

Steve French
Sep 8, 2003

Like, sure, providing autocorrect and never getting poo poo wrong is probably an unattainable goal. But you can at least make the problem a whole lot less bad without being perfect.

vOv
Feb 8, 2014

There is a dashed blue underline when something gets autocorrected... but it goes away as soon as you type a character so it's basically loving useless.

SupSuper
Apr 8, 2009

At the Heart of the city is an Alien horror, so vile and so powerful that not even death can claim it.

EssOEss posted:

I hear a lot about how Unity's .NET/C# functionality is very limited compared to the real thing but I never saw an article covering it in depth with any juicy details. Is there some good reading material to understand it in depth? I want more than horrorsnippets!
There's no in depth article as far as I know, it's all learned from experience by frustrated developers and various random blog posts and docs.

Most of Unity's .NET horrors come from the fact it's just a scripting layer for a native C++ engine, and the API they came up with really wants to pretend otherwise, even if it means brutalizing .NET. So everything that interacts with the native layer makes very little sense from a .NET perspective, because it's not giving you the whole picture and you don't really know what's going on under the hood. The other horror was that up to a few months ago they were stuck on an old Mono version that only supported .NET 2.0.

So let's talk about the UnityEngine.Object (which I'll shorten to UnityObject for clarity):
  • A UnityObject is not like a standard .NET object, it's just a wrapper for an object in the native layer. So it's actually two objects kept in sync by the engine (the native object and the .NET wrapper).
  • Constructing a new UnityObject() manually will return null, because it has no native counterpart. Only UnityObject subclasses like GameObject and MonoBehavior can be constructed like this. Even then, using constructors (or defining your own) shouldn't be relied upon, as they are used by the native engine and will behave unpredictably. You're supposed to use dedicated APIs like Instantiate and Destroy. Note that none of this is a compiler error (it might get you a warning at most).
  • A .NET UnityObject is just a weak pointer to the native UnityObject. The .NET object may be GC without affecting the native, and the native may be destroyed leaving various dangling references. If this happens, the only way to check if the native object is still there is to use "== null". This isn't .NET null, it's an overloaded operator.
  • So there's no way to distinguish between .NET null and Unity null. A "null" UnityObject will still show up fine in the debugger, and accessing it will not cause a NullReferenceException, but a custom Unity one. Using this "null" UnityObject won't always fail the way you expect it to.
  • UnityObjects cannot be serialized by .NET built-ins. They have their own Unity serialization, but that's reserved for the engine/editor, not for you. Likewise, this Unity serialization is designed for UnityObjects, not .NET objects. It doesn't support most .NET containers, generics, polymorphism, circular references, or even any references types at all (they're treated as structs).
Bonus horrors:

SupSuper fucked around with this message at 06:18 on Dec 25, 2017

QuarkJets
Sep 8, 2008

Steve French posted:

As others have pointed out, part of the problem is that autocorrect in a desktop operating system where people are presumably operating with real loving keyboards is real dumb; the other half is that even if you are going to provide autocorrect functionality, it should be made really loving obvious when the machine has taken it upon itself to change what you wrote.

Right? Even 3rd party spellcheck programs that are trying to check everything you type don't just assume to know better and implement corrections for you, rather they have some way of notifying you of a suggested correction (like the famous red underline) that you are free to ignore

Macbooks having autocorrect turned on by default is so Apple: a feature that when implemented perfectly would solve a minor inconvenience but in practice is just a source of frustration

Absurd Alhazred
Mar 27, 2010

by Athanatos

SupSuper posted:

There's no in depth article as far as I know, it's all learned from experience by frustrated developers and various random blog posts and docs.

Most of Unity's .NET horrors come from the fact it's just a scripting layer for a native C++ engine, and the API they came up with really wants to pretend otherwise, even if it means brutalizing .NET. So everything that interacts with the native layer makes very little sense from a .NET perspective, because it's not giving you the whole picture and you don't really know what's going on under the hood. The other horror was that up to a few months ago they were stuck on an old Mono version that only supported .NET 2.0.

So let's talk about the UnityEngine.Object (which I'll shorten to UnityObject for clarity):
  • A UnityObject is not like a standard .NET object, it's just a wrapper for an object in the native layer. So it's actually two objects kept in sync by the engine (the native object and the .NET wrapper).
  • Constructing a new UnityObject() manually will return null, because it has no native counterpart. Only UnityObject subclasses like GameObject and MonoBehavior can be constructed like this. Even then, using constructors (or defining your own) shouldn't be relied upon, as they are used by the native engine and will behave unpredictably. You're supposed to use dedicated APIs like Instantiate and Destroy. Note that none of this is a compiler error (it might get you a warning at most).
  • A .NET UnityObject is just a weak pointer to the native UnityObject. The .NET object may be GC without affecting the native, and the native may be destroyed leaving various dangling references. If this happens, the only way to check if the native object is still there is to use "== null". This isn't .NET null, it's an overloaded operator.
  • So there's no way to distinguish between .NET null and Unity null. A "null" UnityObject will still show up fine in the debugger, and accessing it will not cause a NullReferenceException, but a custom Unity one. Using this "null" UnityObject won't always fail the way you expect it to.
  • UnityObjects cannot be serialized by .NET built-ins. They have their own Unity serialization, but that's reserved for the engine/editor, not for you. Likewise, this Unity serialization is designed for UnityObjects, not .NET objects. It doesn't support most .NET containers, generics, polymorphism, circular references, or even any references types at all (they're treated as structs).
Bonus horrors:

:magical:

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
You can use ReferenceEquals(obj, null) to tell the difference

Volguus
Mar 3, 2009
So Unity recreated the C# language with their own implementation or do they actually have something (minuscule even) in common with .NET proper? I understand the need for an easy to use scripting language (after all, writing a game is hard and you're positioning yourself to make it easy) and I kinda understand the choice of C# as being a quite popular language and relatively easy to use, but the bastardization that they came up with ... that's difficult to digest.

Internet Janitor
May 17, 2008

"That isn't the appropriate trash receptacle."
They started by forking an old version of Mono and then glued on some "conveniences" without, apparently, considering the downsides to fundamentally altering the semantics of the language.

Soricidus
Oct 21, 2010
freedom-hating statist shill

Plorkyeran posted:

It's not impractical in the sense that it costs too much. It's impractical in that having every sequence of characters that someone might want to type in your dictionary simply isn't possible, and would actually be less useful in many cases than a less inclusive dictionary (because many typos are technically words that someone might want to type).

Autocorrect on by default is dumb, but not because of this issue in particular.

Right, so they should have a better concept of confidence: not just “is this sequence of characters the user typed a plausible typo for this word that I know?”, but also “am I confident that the user intended to type the other word, and that what they typed is not in fact a word I don’t know?”

Like “teh” -> “the” is reasonable, because you’re correcting a very common typo to a very common word and your model of English can probably show that “the” is a highly probable word in context. But should you really ever correct any string of letters to “fluoxetine”? No: it’s pretty unlikely anyone will type that word unless they know what they’re doing, and you should know it’s it’s part of a very specialised and constantly growing medical vocabulary so if they mistype it then that is not unlikely to be because they’re typing a different but similar word.

Deffon
Mar 28, 2010

Also, to be clear: this is all proper .NET semantics with operator overloading, native bindings, and reflection that people could implement themselves with .NET. It's just very unintuitive conventions.

Soricidus
Oct 21, 2010
freedom-hating statist shill

Deffon posted:

Also, to be clear: this is all proper .NET semantics with operator overloading, native bindings, and reflection that people could implement themselves with .NET. It's just very unintuitive conventions.

Suddenly Java’s lack of operator overloading doesn’t seem so bad.

Seriously, they overloaded == to report nullness for things that are not in fact null? :psyduck:

The Phlegmatist
Nov 24, 2003

Soricidus posted:

Suddenly Java’s lack of operator overloading doesn’t seem so bad.

Kotlin seems to have implemented them in a sensible way.

C++ lets you overload way too much, including important things like * and & which tend to break everything in exciting ways if you don't know exactly what you're doing.

SupSuper
Apr 8, 2009

At the Heart of the city is an Alien horror, so vile and so powerful that not even death can claim it.

Volguus posted:

So Unity recreated the C# language with their own implementation or do they actually have something (minuscule even) in common with .NET proper? I understand the need for an easy to use scripting language (after all, writing a game is hard and you're positioning yourself to make it easy) and I kinda understand the choice of C# as being a quite popular language and relatively easy to use, but the bastardization that they came up with ... that's difficult to digest.
It's still .NET, it's just their APIs for the native stuff that break all standards. Everything that exists solely in the .NET layer behaves normally. To their credit, they are very very slowly weeding out the weirdest bits, they're just not in any rush to to do so given it's a 10-year old API at this point.

If you wanted to see weird stuff, Unity doesn't just support C#. Oh no, it also supports Boo (a .NET based Python-like), and their very own UnityScript (a .NET based JavaScript-like), all running on the same API. They're on their way out now, thankfully.

Drastic Actions
Apr 7, 2009

FUCK YOU!
GET PUMPED!
Nap Ghost

SupSuper posted:

It's still .NET, it's just their APIs for the native stuff that break all standards. Everything that exists solely in the .NET layer behaves normally. To their credit, they are very very slowly weeding out the weirdest bits, they're just not in any rush to to do so given it's a 10-year old API at this point.

If you wanted to see weird stuff, Unity doesn't just support C#. Oh no, it also supports Boo (a .NET based Python-like), and their very own UnityScript (a .NET based JavaScript-like), all running on the same API. They're on their way out now, thankfully.

They also forked MonoDevelop, and didn’t always port fixes back to their version, leading to people complaining in our repo about bugs that were already fixed :argh:.
With their fixes supporting newer (mainline) Mono, there’s also better support for Visual Studio and VS For Mac. So they are trying now to fix the more :psyduck: parts at least.

Dr. Arbitrary
Mar 15, 2006

Bleak Gremlin
For autocorrect, a first step should be to flag some words as dangerous.

Nobody would have been upset if Fluoxetine had been autocorrected into Florida or Forestry.

Dylan16807
May 12, 2010

Dr. Arbitrary posted:

For autocorrect, a first step should be to flag some words as dangerous.

Nobody would have been upset if Fluoxetine had been autocorrected into Florida or Forestry.

As a bonus, if you have words that can be recognized but not autocorrected to, you make swear words act a lot less stupid.

vOv
Feb 8, 2014

The Phlegmatist posted:

Kotlin seems to have implemented them in a sensible way.

C++ lets you overload way too much, including important things like * and & which tend to break everything in exciting ways if you don't know exactly what you're doing.

But without overloading * you wouldn't be able to implement smart pointers. I agree that overloading & is stupid.

Eela6
May 25, 2007
Shredded Hen
To be clear here, we're talking about overloading the C-style unary prefix * and & used for pointer variables and dereferencing, not the binary operands * and & used for multiplication and bitwise AND, right? Because that's an important operator to be able to overload for numeric types.

My C++ is pretty weak, so trying to follow the conversation.

vOv
Feb 8, 2014

Eela6 posted:

To be clear here, we're talking about overloading the C-style unary prefix * and & used for pointer variables and dereferencing, not the binary operands * and & used for multiplication and binary AND, right? Because that's an important operator to be able to overload for numeric types.

My C++ is pretty weak, so trying to follow the conversation.

Right, yeah.

The Phlegmatist
Nov 24, 2003

vOv posted:

But without overloading * you wouldn't be able to implement smart pointers. I agree that overloading & is stupid.

Yeah. I mean it should be possible to overload them but I've seen crazy abuse of unary & in scientific libraries because unlike unary + and - it shares the high precedence but also doesn't look confusing in arithmetic expressions.

So someone will overload unary & to return the determinant of a matrix or something and make you use std::addressof to actually get the reference.

e: some bespoke math library written by grad students actually did this lol

The Phlegmatist fucked around with this message at 22:03 on Dec 25, 2017

vOv
Feb 8, 2014

Eigen overloads the comma operator so you can do

code:
Matrix3f m;
m << 1, 2, 3,
     4, 5, 6,
     7, 8, 9;

Soricidus
Oct 21, 2010
freedom-hating statist shill

vOv posted:

But without overloading * you wouldn't be able to implement smart pointers.

Yeah it would be terrible if you had to use method call syntax instead of operators to access the referenced values in your memory management containers. Terrible.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
Yes, it would be pretty terrible. Syntactically privileging built-in types results in people using them even when a user-defined one would be more appropriate.

canis minor
May 4, 2011

http://9tabs.com/random/2017/12/23/evil-coding-incantations.html

Absurd Alhazred
Mar 27, 2010

by Athanatos

Plorkyeran posted:

Yes, it would be pretty terrible. Syntactically privileging built-in types results in people using them even when a user-defined one would be more appropriate.

It then becomes the responsibility of the API writer to make sure that the semantics are not too out-of-touch.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The worst part is overloading || and &&, which also silently makes them non-short-circuiting.

b0lt
Apr 29, 2005

Jabor posted:

The worst part is overloading || and &&, which also silently makes them non-short-circuiting.

In the same vein, overloading the comma operator makes it go from evaluating expressions left to right to implementation defined behavior.

Soricidus
Oct 21, 2010
freedom-hating statist shill

Plorkyeran posted:

Yes, it would be pretty terrible. Syntactically privileging built-in types results in people using them even when a user-defined one would be more appropriate.

That’s a good argument for allowing overloads of things like arithmetic operators and []. Less so for unary *, since raw pointers are still syntactically privileged at the point of definition, and using a different idiom for smart pointers and iterators would have allowed any use of pointer syntax or pointer arithmetic to become a code smell.

Sedro
Dec 31, 2008

Jabor posted:

The worst part is overloading || and &&, which also silently makes them non-short-circuiting.

C# does have short-circuiting via some craziness fit for this thread. You overload the true and false operators for the type as well as the bitwise AND and OR. Then x && y becomes operator_true(x) ? operator_and(x, y) : x.

Scala has the best answer I've seen. There's no operators, just methods with non-alphanumeric names, and short-circuiting is trivial with call-by-name.

Absurd Alhazred
Mar 27, 2010

by Athanatos

Soricidus posted:

That’s a good argument for allowing overloads of things like arithmetic operators and []. Less so for unary *, since raw pointers are still syntactically privileged at the point of definition, and using a different idiom for smart pointers and iterators would have allowed any use of pointer syntax or pointer arithmetic to become a code smell.

Interestingly enough, Microsoft decided to use ^ and % to replace * and &, respectively, when referring to CLR managed memory objects, instead of either overloading or using std::shared_ptr<T>, etc.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Soricidus posted:

That’s a good argument for allowing overloads of things like arithmetic operators and []. Less so for unary *, since raw pointers are still syntactically privileged at the point of definition, and using a different idiom for smart pointers and iterators would have allowed any use of pointer syntax or pointer arithmetic to become a code smell.

Making raw pointers valid iterators without an adapter (and all the accompanying design trade offs) would be a terrible idea if the whole thing was being designed from scratch, but it was a key part in getting people to actually use the STL algorithms in the days before compilers could optimize thin wrappers out of existence, so even in retrospect I think it was the right decision.

Dylan16807
May 12, 2010

Sedro posted:

C# does have short-circuiting via some craziness fit for this thread. You overload the true and false operators for the type as well as the bitwise AND and OR. Then x && y becomes operator_true(x) ? operator_and(x, y) : x.

Yeah, that one has always impressed me. They clearly had very specific use-cases in mind for coercing values to true or false. Don't implement true and false for numeric types or you'll suddenly find that 4 && 8 is false.

vOv
Feb 8, 2014

Soricidus posted:

That’s a good argument for allowing overloads of things like arithmetic operators and []. Less so for unary *, since raw pointers are still syntactically privileged at the point of definition, and using a different idiom for smart pointers and iterators would have allowed any use of pointer syntax or pointer arithmetic to become a code smell.

You'd still need raw pointers if you wanted to construct a vector of things you don't own, since you can't have a vector of references (and the same goes for many other container types).

I agree that pointer arithmetic is bad 99% of the time but you can't do it with smart pointers anyway.

Absurd Alhazred
Mar 27, 2010

by Athanatos

vOv posted:

You'd still need raw pointers if you wanted to construct a vector of things you don't own, since you can't have a vector of references (and the same goes for many other container types).

I've got good news!

OneEightHundred
Feb 28, 2008

Soon, we will be unstoppable!
I'm still waiting for that to conflict with a standardized change in some future edition of C++ and bite them in the rear end.

There are some good arguments for not using shared_ptr due to the semantic differences (i.e. CLR objects can be moved), but it'd have been much better if they had used "managed_ptr<T>" or something that didn't require new syntax, which they did do for arrays.

Adbot
ADBOT LOVES YOU

Absurd Alhazred
Mar 27, 2010

by Athanatos

OneEightHundred posted:

I'm still waiting for that to conflict with a standardized change in some future edition of C++ and bite them in the rear end.

There are some good arguments for not using shared_ptr due to the semantic differences (i.e. CLR objects can be moved), but it'd have been much better if they had used "managed_ptr<T>" or something that didn't require new syntax, which they did do for arrays.

That would not be a very Microsoft thing to do. :v:

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply