What is the use case for delegate?

Lol, assuming someone who uses an overly complex keyword has more experience, that’s funny.

Someone restricting a developer to certain methods is not someone having “more experience”, that’s restricting a potential developer of certain methods, the total opposite.

Haha, I’ve literally learned every single thing I know about Crystal mostly from help on Gitter and GitBook. You saying I don’t learn from others is simply untrue.

One of the main goals of object orientation is encapsulation (https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)#An_information-hiding_mechanism). If you expose all the inner workings of your class, they are effectively now part of the interface you are exposing to the user. Which means you can no longer change the internals (e.g. delegate some method to an entirely different type of class) without possibly breaking backwards-compatibility. With encapsulation and a clean interface also means you (the designer of the object) can know in exactly which ways your internal state can be modified. If the users of the class can make arbitrary modifications to the class’s internal state it can turn into a maintenance nightmare.

The trade-off is of course, like you said, if something is private, a use-case which the original developer didn’t think of might be harder to achieve. But in most cases that’s a small price to pay, and if it’s a well-managed project, they’ll probably accept a request to accommodate your use case.

1 Like

Restricting the end-user to only a public API is bad design and very limiting.

This is the entire point of libraries - To encapsulate and abstract the underlying logic and data structures. I actually like using this kind of abstraction to provide a single public interface that calls multiple modules under the hood. It doesn’t mean that you don’t have to expose the nobs to tweak at all, just that they’re not the first place to jump in.

In the likes of Elixir, this is very common. You can choose to hide functions or entire modules from generated docs, use defp to declare functions as private, and use defdelegate as a way to provide a public API that can send to a ‘private’ module.

1 Like

If I’m making a library, the worst thing I can do is make end-users suffer by restricting them to certain methods. I’ve seen it happen in the Godot repo so many times, it’s really sad. Users are constantly creating issues asking for methods to be exposed (made public), just so they can use their functionality to fix their problem. Restricting the developer to code is never a good idea.

Think of an actual library. Users who want to check out a certain book to gain access to that information, should not have to ask permission from the manager of the library just to check the book out. They should be able to check it out freely as you normally would (scanning your library card, etc). Not depend on someone else to give you permission.

To take your analogy of a library with books, should anyone who goes there be able to tear pages out of any books there and just take the pages? Should they be able to take books if they don’t have a library card (which incidentally requires permission to acquire)? What if the way they want to read a book is to remove its binding and spine and array all the pages on the floor in front of them; is that an acceptable use of the library? Even in real life, there are certain boundaries that allow things to work the way they are supposed to.

Going back to software development, these kinds of boundaries can help with understanding what code is supposed to do. If I write an implementation of a stack, which is basically an array that you can only add to, access, or delete from at the end, it shouldn’t matter whether it’s an array internally or some other thing. Someone who is using a stack should know why they’re doing that, and so they should never need to access anything except the end. If they’re using a stack and find that, for some reason, they need to access something in the middle, then they need to consider 1) if they really need to do that, and 2) whether they should be using a stack. The answer to one of those questions will be “no”.

There are some cases in which things which aren’t accessible to a developer should be. However, most of the time if you’re making a library it’s better to have everything private except what you know you want to be public. One reason is what Hinrik mentioned: it’s better if you can improve your library without breaking anyone else’s code. If real-life libraries allowed some of the things I mentioned above, people would do them. If it gets them what they want in the moment, most of the time people won’t worry about what the long-term consequences will be. Similarly, if I allow someone to use the array that my stack is based on, they will. It doesn’t matter how many warnings there are in the documentation or even that it’s called a “stack”. So when I decide later that there’s actually a clever way that I can use a hash or set or slice or whatever instead of an array, I will break their code. We obviously want to minimize broken code (though there are good reasons to do it anyway), so we should restrict their access in the first place.

However, even without considering broken code, creating a library involves making promises to the user. Part of that is behavior: if my user wants to put something on their stack, it should put it on the stack so they can get it later. However, they should also be able to rely on that thing being the same if it’s been in the middle of the stack for a while. It’s helpful to my user if they aren’t allowed to mess with the middle of the stack because then later, when they are getting things from the stack, everything is still where and how they expect.

I wanted to end this with another example of using delegate that doesn’t fall under the stuff I (and others previously) have talked about. After all, you didn’t ask a question about why variable and method privacy exists. Unfortunately, though, I have to go. I’ll try to remember to add to this later with a good example of when you can use delegate, even if you refuse to believe that the reasons we’ve given are good ones.

3 Likes

This doesn’t really work because we are given permission by the core developers/company of the particular repository to download and use the code. That is our permission, which now we can use any code we see fit in our codebase (and not be hindered by private abstract def virtual annotated garbage method names).

I agree with this because that is low level development. Which is vital and essential for certain apps to run. Of course you don’t want a passenger being able to fiddle around with the joystick on an AirBus. That’s obvious. You want trained professional pilots to operate the plane (in your case, coding and being in charge of a nice stack).

However, the passenger is allowed to go to the bathroom, talk, express emotion, etc. All freely without asking the pilots for permission. Imagine the passenger having to ask before they can talk or go to the bathroom? It’s silly, just like private methods/variables. You are limiting a developer (passenger in this example) to exercise their rights and code freely. You are restricting them.

This analogy with software development is that the bathroom, the ability to talk, express emotion, etc… is part of the public API, the part that users of your library is authorized to use (and which will be stable in the future).
However in an airplane you are not allowed to open up any drawers in the bathroom or in the flight attendant area to remove something you don’t want or the change something you’re not supposed to change (e.g: because you don’t know the ‘hidden’ implications this would have).

1 Like

Problem is what if the pilot suffers a heart attack (a bug in the software), and now the passenger who happens to be a trained pilot, cannot fly the plane because there are steal beams blocking the cockpit (all the code in the library is all private and not available). Now the plane crashes.

As I said, developers should have every right to access any method/variable/etc in a library.

But please, continue to tell me how I am wrong

You are wrong.

3 Likes

You are wrong.

The whole IT progress has been about abstractions and isolation. Why does protected mode exist? Why do you have to fiddle with IPC instead of directly reading and mutating memory of other processes?

The less API surface you have the better. Crystal offers you an enormous help with regards to open classes so that you are able to monkey-patch anything anywhere to fit your particular usecase, but that doesn’t mean everyone should do that all the time.

Going against the consensus is fine as long as you have a good argument, however that also requires understanding existing solutions. I don’t believe you’ve done the latter part.

1 Like

ok

I’ve got a great understanding of it, and it’s definitely a detriment towards developers. Just look at all the issues in the Godot repo of users asking to make methods public so they can fix their issue. Making methods private hinders the development process of the developer.

This isn’t the best argument of why the well established concept of encapsulation is bad.

So far your supportive points in your argument have been:

  1. Look at the issues Godot has
  2. Becuase I say so

I’m sure all of us would agree that there can be a problem with having not enough exposed in the public API.

Having someone make a request to expose something is better than them using something that wasn’t intended (at that moment) to be public and having their app break when that (still non public) part of the library is changed. If someone has a valid use case for why that part of the library should be public than I’m sure Godot or any other library would be happy to discuss an implementation that provides that feature, defines the public API in how it should be used, and updates the library’s internal implementation to use either that new public API or a new refactored internal implementation.

This issue isn’t as simple as make all things public or everything should be private but providing a good middle ground.

Let’s do can example related to your game. Say you introduce the concept of mods. You allow people to define some code that changes how the game looks/runs, but in a non game breaking way in order to keep things fair. A mod is created by using a base shard you developed (similar to say crystal-db), of which you have everything public. Someone wants to make a custom sword, so they inherit from your abstract base Weapon class and define some required methods to define how this weapon works, the stats, cost, etc. Within your base Weapon class you have some logic that
ensures the cost/stats of the weapon don’t get too out of hand to make things unbalanced and give a player an unfair advantage. However, this player notices that everything is public and instead of using the public API, he sees he can directly call create_item, and pass in arbitrary values, effectively bypassing the fairness checks. This player now has a weapon that is a 1 hit kill on everything and weighs nothing.

You could argue that “since everyone can do it its ok”, or “it’s about having fun so they can do what they want”. But if you’re the owner of a public game server that people are playing, with a defined list of rules in order to make the game fair and fun for everyone involved, whom also may also be paying you money. You have an obligation to maintain the fairness and fun of the game. What fun would a game be if, essentially cheating players, were running around with modded weapons/armor high above anything that should exist. The game would now be toxic and exclusive to only those that know how to develop mods to compete. You broke the promise you made to your players. The idea that everything should be public ruined the game.

(Granted Crystal is very liberal when it comes to encapsulation, but you get the idea of how it would have helped here).

3 Likes

@girng_github When programming “in the large” with hundreds of developers, these seemingly trivial isolation boundaries begin to work in your favor. If you’re building an internal library for just a handful of engineers it may feel restrictive, but you have the advantage of locality, communication, and agility to change at your disposal.

Now take those elements away and imagine a world where the code must fend for itself and maintain its integrity in making good on its API. Now imagine you’ve just written an SSL library. There’s no room for error - the API surface must be small, foolproof, and bug free. Exposing the knobs and dials and levers will lead to problems, which will then be blamed on your library for not protecting library consumers from themselves.

If exposing the API via microservice, take what you think should be public in the lib and cut 50~75% … that’s probably about the number of fn()s that should survive on to a language agnostic RPC interface via REST, gRPC, or the like. If developers want more functionality, then they have to take the next step and compile against a library with more. If you expose it all online then you have to anticipate how every function can be abused, either for DDoS, to crash the executable in non-safe ways searching for privelege escalation, or service quality type attacks like keeping connections open or hogging some other resource CPU/RAM wise. The more that’s public the less secure the library will be, and therefore the less reliable in fulfilling its promises.

Consider also that as of 2019 software no longer runs in a legal vacuum. Even with disclaimers, if you run a popular site and it gets hacked, the developers and site operators can be held liable for any amount of information about users that’s leaked or scavenged from your service. In Europe these fines are stiff. In the US, similar privacy focused laws are in the pipeline - it’s just a matter of time.

3 Likes

It’s a real world issue, I gave you a concrete example of it happening right in front of our very own eyes. I’d say that is a pretty good argument. Developers should not be hindered by private methods.

Replace the quote with Encapsulation hinders developers. That GIF essentially represents your argument.

Also read the rest the rest of my reply.

1 Like

This depends if that game is on the server, or client-side only. If it’s server-side, then I agree. You obviously want restrictions so other players don’t suffer and one player become extremely over powered.

However, if it’s solely a client side game with modding, players should have the power to do whatever they want, with any item/system they want. I see this as a feature, not an issue.

Imagine if the developers of Crystal made tcp_nodelay private. A user developing a gameserver wonders hmm, wtf why is there a lot of latency between game packets?!?. So they try to disable Nagle’s algorithm, but cannot. So they now have to create an issue and ask for it to be public. It’s silly, counter-intuitive, makes end-users suffer, and a colossal waste of time. Not only for the end-user, but the developers when it should have been public in the first place.

As others have mentioned it needs to be a balance between protecting the internals of the library while exposing enough to allow the user what they need to do.

I would much rather create an issue than depend upon something that I have no guarantee of it working that way tomorrow, or next week, or next month.

So in other words: Let developers suffer and have a hard time with the library until they take time out of their day to inform you to fix it?

Honestly I see no way forward here. Different people have different preferences.

There are people who unironically believe that they can be productive using only pure functions. My personal experience tells me otherwise, the difference here is I don’t tell them my opinion, I just continue to be amazed.

@girng_github: you do you, let nobody tell you how to live, but if you ask a question, it would be polite to listen to the answers and understand them.

1 Like

@girng_github You act like it’s the end of the world if you have to spend the 10min it would take to say I would like access to x for reason y. Then the maintainers will either say no use z, or will look into how to best expose that thing you need.

Either way, I’m done arguing over this, is just like abstract methods all over again.

1 Like