ā Confusion as to what to default to when it comes to accessibility modifiers
So I come from a extensive C++ background, in which we use the keywords:
public
and private
a bit different. They say everything about accessibility but nothing about assemblies and whether we are allowing external assemblies to access our classes, methods and even members.
Now to my understanding internal
is basically public
but within the assembly im working in, meaning that is how I say: this func()
method is public and can now be called on its respective object outside of the class. And public
is used to say: hey, this is allowed to be called form another assembly and is public
within its own assembly too.
Now, knowing this, I concluded that best practice, granted we work within one assembly, the internal
keyword is the default one should use however I'd love to get some assurance on it. Since even my IDE defaults to public
when auto-generation ctors, methods, etc.
154 Replies
As shown above, it seems, unnatural? Do people go by the ideology of: "Just make it public unless you have a reason it shouldn't be accessible by other assemblies"
Usually, yes, when it comes to classes, interfaces, structs, records, and enums you default to
public
It's only with methods that you start worrying about accessibility
That being said, some people do swear by giving everything the lowest accessibility possible, like internal
for classes, interfaces, ..., and enumsInteresting, how come methods are treated more strict in that regard?
Very often you work with just a single project that isn't meant to be used as a library
It's worth mentioning that a public property in an internal class.... is essentially internal
So accessibility from the outside is whatever
But accessibility within the project matters always
a
internal
class overrides all its methods and members accesible modifiers?Not really
More like, children having higher accessibility than parent makes no sense
if the class itself is "hidden", the accessibility of its members is irrelevant
ah
ye
If I can't use a
InternalThing
class in my project... I can't exactly use InternalThing.MakeStuff()
you'd hope this gives a compile time error
or at least, a warning?
it does if you try to use it, sure
a bit too late in my opinion, but I guess it has its reasons
huh?
Wym "too late"?
Do you want error messages as soon as you think of doing it or...?
I would want it to warn me that my access modifier makes no sense
how much earlier could it be than something that pops up in your IDE
Yeah, if the class is internal, and my method is public
that wouldnt make sense
it does, if that "makes no sense" in a way that is actually logically nonsense
and wouldnt work?
sure it would
the method, if it were not public, would not be visible even if you can "see" the class
like... I can't imagine this works differently in C++ either
Okay, lets say you have:
I assume, granted im in another assembly, I couldnt even make an object of
A
, so regardless of func()
being public it wouldnt matter?Yeah
Correct
In fact, as far as assembly b is concerned that class doesn't exist
But it matters for this project
yes, but just use internal?
better practice then no? clarity of assemblies and its made "available" in its own assembly
The point is that each "level" of accessibility builds on the other. You only care about the accessibility of type members if you can see that type to begin with
Anything you make public or private (or whatever else) in one type assumes the consumer knows what that type is, in the first place
Overkill imho. The class is internal, so it's just moot to change the method too
There's no room for contradiction in this, it's a conceptual misunderstanding
mhm, actually, yeah probably is overkill. Considering you typically dont care about other assemblies just marking the class internal (its that by default), is good enough
and then you treat public as if its only talking about the current assembly (within a class that's internal of course)
I can see the argument in that, so common practice is just to write classes:
Since,
HumanEntity
isnt available to any other assembly any way we disregard caring for thatBasically, although people usually prefer explicit over implicit so that
internal
would be there
Just a convention thoI see, makes sense - I'll just write it too then.
Sorry, its a lot to take in from multiple people at the same time. Are you saying I have a misconception somewhere, if so, please could you point it out for me bcs as of right now I am not sure where!
The point is that each "level" of accessibility builds on the other. You only care about the accessibility of type members if you can see that type to begin withyes, I share that thought now
I took one of the things you said to mean that you think e.g. "internal class {public method}" was inconsistent
if that's not what you meant, the mistake is mine
well originally I thought that it'd be better practice since its clarity but since Pobiega and you all mentioned its pretty much overkill!
Thanks a ton though everyone, I have a much better view on it all now. Apologies if I missed some replies.
Keeping things as "locked down" as possible might be a good idea, yeah.
My point was just that an access modifier applies to that one particular thing (type, method, whatever). If that happens to be e.g. a class, whatever access modifiers you give its methods/members only matter if that class is accessible.
Yeah, makes sense. It seems you dont seem to be the only one to think that way as both ZZZ and Pobiega say the same thing. Seems like I'll be explicit about the internal on a class level, and use
public
on its methods and members!š
Im not sure if there is an official convention about it, but thats how 99% of C# code I write/read is
we could talk about
sealed
tooEh, it's not an accessibility modifier
It's just a "you can't inherit from this" modifier
yeah i know but it kinda have, potentially, a similar importance, in terms of standard to mantain in the code (i don't know if i expressed that in an understandable way)
Eh, kinda. I'm part of the "sealed by default" gang, but this discussion wasnt about the idea of internal classes, rather why properties and methods wasnt also specified internal
i just thought that an experienced programmer coming to c# would benefit to know at least that this exists as a concept
Sure, but what says he doesn't? its not an access modifier
its the equivelant of
final
in C++yep
its a great tool, I use it a lot in production code. I dont default to it, but its a way to enforce not inheriting from a class that's intended to be inherited from!
@chaos_solo Thank you though, I didnt know
sealed
was the keyword they used. I figured it'd be final
like in C++ and java.you would have found out sooner or later, i guess
Just like with anything, either from people like you or the internet!
I only default to
sealed
records. They're immutable, might as well lock them down furtherthats interesting
records is where I don't default to sealed lol
That, and I mostly used them just for data in/out
because they are immutable, its not really a big deal if someone extends them š
I'd rather not have my
UserDto
inherited fromfair
I actually use record inheritance to build certain DTOs
like
CreateUserDto
and ModifyUserDto
are the same, except modify adds an IDi was trying to isolate value objects too
But then you need to add a prop to
CreateUserDto
that ModifyUserDto
doesn't need, and...
I like my DTOs entirely self-containedeh? no?
Even if they repeat themselves
you duplicate even enums?
modify is just create + id
if you ever add something to create that doesnt go in modify, then you can copy at that point - but the idea is that they stay the same
Well, sure, but let's say
Create
also needs a CreatedBy
prop to identify who created the item, and you don't want that to change so this prop should not be in Modify
thats not a sideffect, its intentional
Sure, if you have something like that then keep them separate
I'd rather just have DTOs self-contained for cases like that, by default
But to each their own ofc
I never saw/used a
record
, I understand its a valuetype thats immutable. But isn't that somewhat what a struct entails, a readonly struct
that is?It's a reference type, actually
It's a spicy class
but its members are value types?
Whether members are value or reference types depends on... their types
A struct can have a reference-type member
A class can have a value-type member
yes, on second thought that was a stupid question
I wont lie this whole value type, reference type is new to me.
Records are classes that behave like value types (comparison by value) and have added immutability and some other useful stuff like a deconstructor
Reference types are just pointers tbh
Kinda-sorta
yes thats how I look at them
but in C++ a reference != a ptr
a reference is an alias, I suppose its the same for C#
dtor's arent possible in a class/struct, normally?
They are
But you need to write them yourself
With records, you get it for free
there's no default dtor/ctor?
Angius
REPL Result: Success
Result: <>f__AnonymousType0#1<int, string>
Compile: 594.961ms | Execution: 104.759ms | React with ā to remove this embed.
I'm not talking about a de-structor but about a de-con-structor
looks like brace initialization
lol
(destructors in C# are called finalizers btw)
its basically construction it in place
this is the relevant bit tbh
var (a, b) = f;
into a tuple
just like that lol?It's not a tuple, it's how you deconstruct... things that have deconstructors
So tuples, records, anything else you write a deconstructor for
new term it seems
deconstructors, basically help you grab the contents of a record into specific types
(swap in place with tuples is a cool trick btw,
(a, b) = (b, a);
)yes bcs it doesnt care about the field names right?
it just copies b into a, and a into b
Yep
It's positional
ye, I would've uninstalled CLR if it wasnt
š
Okay, so record's just have deconstructors that help you de-con-struct its properties into types
much like going from a tuple into just, variables, conceptually that is?
They have all of this, actually
But yeah
The deconstruction behaviour is like that of a tuple
much like this, conceptually
ye
though i prefer:
(string name, int age) joren_data = NameAndAge();
we have auto
in C++, which I use for long types but normally I'd say type clarity is importantYou should be able to do that
in c sharp ppl seem to spam
var
, that scares me lol
cus in C++ that usually result in ppl fucking upAngius
REPL Result: Success
Compile: 403.645ms | Execution: 61.001ms | React with ā to remove this embed.
ye
auto
doesnt deduce reference for instance
ye I do that, I think its better practice
lol
var
should be limited to longer unbearable types to writeThe recommendation in MS docs is to always use
var
like this:
Well, since C# is much more dummy proof than C++ I can see why they are okay with it
but for new programmers spamming
var
is a good way to be unaware of what you're actually doing
also becomes harder to read code sometimes
lol
not knowing the type instantly, especially if its not your own codeC# won't let you shoot your foot, thankfully.
var
isn't dynamic
yes and no. its hard if you read the code without an IDE, and people use bad names for variables/methods
And IDEs help
Worst case scenario you're gonna get a red squiggle that you can't assign int to string ĀÆ\_(ć)_/ĀÆ
Well, this
func
needs to have its return typevar
wouldnt work?No
var
works only for local variables
Doesn't work for members actually
really rough
you'd end up with an using alias
in this case then, still kind of sad
it should be able to deduce the return type based on the return statement
you'd think
That's why target-type
new
was introduced, so you don't have to do
and can just
instead of
this is inside a class?
Eh, I like it this way better, because the method signature is self-documenting
Yeah, a field, a class member
i see, well its a nice addition
will never use it
Although you can use target-type new everywhere
I believe types should be clarified in a class
but maybe I need more of a dynamic way of thinking
regarding C#
What do you mean by that?
Well when I look at a class, when I skim through one I havent written I'll look at the left part of it, the types and the names
and thats how I get a quick grasp
Yeah
mind you that doing
var _someField = new Foo();
is not normal
in C++
and many languages
noone does this, they use the ctor initializer listThankfully you cannot do that for class members
or just the ctor
Class members cannot use
var
oh
That's why target-type new was made
whats with the
field
then
can you show me a complete examplepublic Foo MyFoo { get; set; } = new();
Used to be:
Is now possible:
Was never possible, just a hypothetical:
thats a property with a default value
oh
I see it now
Far as fields go... $structure
For C# versions older than 10, see
$StructureOld
public Class() {} // Constructor
is not redundant
lol
whats w c sharp and having no default ctors unless explicitly defined?It is redundant
oh
I see, makes sense
[Attribute]
, this flag, what does it mean?It's metadata, really
It can be... whatever
its an attribute, compile-time static metadata
And whatever you do with this metadata is up to you
mostly used for reflection
reflection is a thing in C#
You can use it with reflections, you can use it with sourcegen
now its getting scary
Half of C# frameworks, desktop and web, would not work without it lol
reflection is used often? or is it more a fancy feature ppl dont use
Now, thankfully, we have source gen nowadays
nvm
sure is used often then
lol
Yeah
Guess I'll be diving into it at some point
But Microsoft is pushing AOT now, and reflection is incompatible
So support for source gen and other reflectionless ways increases
interesting, never used reflection if im being honest
so
suppose itll be my first time
You don't really use it that often manually
I used it, like, 5 times
Once because I was too lazy to register all my enums with the NpgSQL driver
Twice because I wanted to add some automatic components for my project, that would generate fields for a form based on a class
The first one is scheduled to be rewritten to a source generator
Mhm, def doesn't sound like a priority to learn for me then yet. Honestly wondering if my learning source is effective, im just reading the Tour of C# and spitting through the docs, works fine bcs of my programming experiences, but tons of details and not a lot of overview and best practices. Any recommendations for such?
I learn best by doing tbh ĀÆ\_(ć)_/ĀÆ
So my recommendation would be... try to make something
Google your way to completion
Come here if you need ungoogleable help
but with return types like that you can simplify your life by letting vs write it, anyway
you write some crap and then use popup menu to correct it
Yeah or a type alias if its used in other places (the same exact type)
Yeah, you can type alias tuples nowadays
Or... just make it a record lol
or start writing it in a method assigning it to a var, and then select it and do extract method
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.