C#: Benefit of explicitly stating "unsafe" / compiler option
Asked Answered
G

9

8

I understand pointers and the rare need to use them in C# code. My question is: what is the reasoning behind having to explicitly state "unsafe" in a block of code. Additionally, why must a compiler option be changed to allow "unsafe" code?

Bottom Line: What in the CLR (or language specs) makes it so we can't just use pointers whenever we want (much like C and C++) without having to type "unsafe" and change the compiler option?

For clarification: I know what "unsafe" and "safe" code is. It's just a question of why must we do all the extra work (ok, not THAT much extra) just to be able to use these features.

Gingivitis answered 3/3, 2009 at 16:37 Comment(0)
P
9

There's an interview with C# Creator Anders Hejlsberg that touches on the subject here. Basically, exactly what @Marc Gravell said: typesafety first, unsafety by explicit declaration.

So to answer your question: nothing in the CLR prevents it; it's a language idiom designed to allow you to work with safety gloves when dealing with types. If you want to take the gloves off, it's your choice, but you have to make the active choice to take the gloves off.

Edit:

For clarification: I know what "unsafe" and "safe" code is. It's just a question of why must we do all the extra work (ok, not THAT much extra) just to be able to use these features.

As mentioned in the interview I linked, it was an explicit design decision. C# is essentially an evolution of Java and in Java, you don't have pointers at all. But the designers wanted to allow pointers; however because C# would typically be bringing in Java developers, they felt it would be best if the default behavior be similar to Java, i.e. no pointers, while still allowing the use of pointers by explicit declaration.

So the "extra work" is deliberate to force you to think about what you are doing before you do it. By being explicit, it forces you to at least consider: "Why am I doing this? Do I really need a pointer when a reference type will suffice?"

Primarily answered 3/3, 2009 at 16:46 Comment(0)
B
7

It is largely about being verifiable. By stating unsafe, the gloves are off - the system can no longer guarantee that your code won't run amok. In most cases it is highly desirable to stay in the safe zone.

This gets more noticeable with partial trust (addins etc), but is still valuable in regular code.

Beall answered 3/3, 2009 at 16:40 Comment(6)
So basically, it's MS trying to keep us from making the same mistakes as were much easier to make in C++?Gingivitis
From MS: C# code that makes low-level API calls, uses pointer arithmetic, or carries out some other unsavory operation, has to be placed inside blocks marked with the unsafe keyword.Mattress
# From MS: In some cases, unsafe code may increase an application's performance by removing array bounds checks.Mattress
msdn.microsoft.com/en-us/library/ms228628(VS.80).aspx msdn.microsoft.com/en-us/library/t2yzs44b(VS.80).aspxMattress
The array bounds checks happen anyway (at the JIT) if you don't host the ".Length".Beall
@Marc Gravell: I think you mean "hoist". :pPrimarily
L
3

Actually the CLR makes no requirements at all about an /unsafe switch or keyword. In fact, C++/CLI (the C++ language that runs under the CLR) has no such /unsafe switch, and pointers can be used freely on the CLR.

So I would rephrase your question as "Why does C# require the use of /unsafe before pointers can be used?" And the answer to that question is as stated in other answers given here: to help the user make a conscious decision to lose the ability to run in anything less than Full Trust mode on the CLR. C++ virtually always requires Full Trust on the CLR, and C# can whenever you call code that requires Full Trust, or whenever you use pointers.

Legendre answered 3/3, 2009 at 16:57 Comment(1)
Exactly. I did rephrase the "bottom line" portion earlier. I use C++/CLI quite often, and it is infact the reason I ask this question about C#.Gingivitis
H
2

When you use an unsafe block, it has the effect of making the code unverifiable. This requires certain permissions to execute and you might not want to allow it in your output (especially if you are in a shared source environment), so there is a switch in the compiler to disallow it.

Heterogynous answered 3/3, 2009 at 16:41 Comment(0)
P
2

Think about it from the opposite point of view: because it's not marked unsafe, you can infer that most code is "safe" by default. So what does it mean to be "safe"? For .Net code, this includes (but may not be limited to):

  • The garbage collector can do business as usual.
  • References to a specific type will refer to objects of that type (or null).
  • Code is guaranteed to comply with .Net trust/security requirements.
  • The code is mathematically proven not to directly touch memory outside it's own AppDomain. It may seem trivial, but imagine if you have multiple AppDomains in the same application. The programmer can confidently treat them as logically separate.

Any time you use pointers you have the chance to break any of those guarantees. Therefore marking code as unsafe gives up those protections.

Preserve answered 3/3, 2009 at 16:47 Comment(0)
U
2

In short, .NET wants you to state your intent.

Sure, the compiler could infer the need for the "unsafe" flag. But the designers want it to be a deliberate decision.

To me, it's akin to a number of syntactic requirements in C#:

  • no switch case without break
  • no access-level "sections" (such as the "public:" marker in C++)
  • no class fields using "var"

The pattern is that you shouldn't move or change one thing and inadvertently affect another. Within reason, they want to keep you from "shooting yourself in the foot."

Lots of great, informative answers here — maybe this goes more to your question.

Unlike answered 3/3, 2009 at 18:5 Comment(1)
var shouldn't be on your list. Allowing type inference at the class level would require a radical redesign of the compiler and may be impossible.Lenity
H
1

So that it is immediately obvious which code won't run in web services without elevated permissions, etc.

Halfbaked answered 3/3, 2009 at 16:40 Comment(0)
M
1

Nurturing good habits & security. Whenever you use an unsafe block in an assembly, a NativeCode permission will be demanded from the stack. This could of course be done implicitly, but couldn't we also just remove the private keyword completely? I think it's good to force developers to specifically require unsafe code before they can use it.

Machute answered 3/3, 2009 at 16:41 Comment(0)
G
1

The most significant difference between safe and unsafe code is that unsafe code is unreachable by .net's garbage collector. Automatic GC is a huge part of the vernacular of .net and, when you go beyond its boundaries, you change a lot of what can be assumed about your code.

Pointers in particular allow for the creation of objects on the heap with no GC references. This leads to another excellent reason to require code to be marked as "unsafe." It makes it easy to narrow down where a memory leak is coming from when you realize you have one.

Goldstein answered 3/3, 2009 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.