Jump to content

Dalija Prasnikar

Members
  • Content Count

    1067
  • Joined

  • Last visited

  • Days Won

    91

Everything posted by Dalija Prasnikar

  1. Not exactly... there are slight differences in behavior. Not that this part matters when you are choosing between inheritance and composition (as general term)
  2. It always depends on particular situation. Both composition and inheritance have their place. Sometimes you can use either, sometimes there is a clear distinction. Some tips that can help you decide. IS-A - inheritance - Sword IS-A Weapon so Sword should inherit Weapon HAS-A - composition or aggregation - Unit HAS-A Weapon so Unit can be composed with Weapon object With simple classes that satisfy IS-A condition plain inheritance will do. With more complex classes, you may want to use composition or delegate some behavior to other classes, especially if that behavior can be reused independently. Delegation - delegate behavior to another class when it is not an objects responsibility to implement behavior on its own Composition - when object is gone the composed objects are also gone - when Pizza is gone so are the ingredients Aggregation - class is used as a part of another class, but still exists outside that other class - when Unit dies Weapon still exists
  3. Dalija Prasnikar

    Check for override

    That change was not worth while even back then. You had two variants for Seek and it was very easy to use wrong one. If you used 32 bit one on streams that support 64 bit your code would only work for streams smaller than 2GB. Change didn't affected older code, but it had permanent negative effect on new code. I encountered such bugs myself, and also have seen others bumping into it on numerous occasions. Yes, at the end our code was at fault, but it was really easy mistake to make. There was several bug reports around that issue at the time in old Quality Central.
  4. Dalija Prasnikar

    Check for override

    YES, backward compatibility matters. But in cases where backward compatibility causes more trouble down the road, then it is not worth the price. In this case, maintaining backward compatibility also opened TStream and descendant classes to subtle bugs when working with streams larger than 2GB.
  5. Dalija Prasnikar

    Delphi 10.3 and the NOX emulator running Android 7

    If your Note 8 has Oreo 8.0 OS then debugging does not work because Google screwed up on OS level. You need to update OS to 8.1 that fixes the issue. It was not something EMBT could fix. http://blog.marcocantu.com/blog/2017-december-delphi-android81-debugging.html
  6. Dalija Prasnikar

    10.3.1 has been released

    To some extent theming has a purpose because without it you could not have dark theme. Problem here is that Delphi (VCL Styles) based theming is just horrible since day one (even before it was introduced in IDE). Instead of VCL Styles being fixed and then used at large, EMBT choose to use VCL Styles without fixing issues. Another problem is not that just in theming itself, but revamping Options dialog layouts without making proper alignment/size adjustments - so everything visually just falls apart.
  7. Dalija Prasnikar

    Recursive anonymous functions

    var [weak] fib: TFunc<integer,int64>; Marking it as weak breaks the cycle. However, there was a bug with weak that is only recently fixed (not sure whether in 10.3 or 10.3.1)
  8. Dalija Prasnikar

    10.3.1 has been released

    Error Insight has always been Error Inside. It never worked properly, and was always lagging behind.
  9. If only making good examples would be so simple.... it is so much easier to trash other people's examples... Joking aside... bad examples (or ambiguous examples) can make more damage than good. OOP is complex matter and not always straightforward. Ask 100 experts about it and you will get 100 different answers. My rule of thumb is learn about OOP, design patterns, testing and then apply common sense over it. If some rules collide, then apply KISS (Keep it simple, stupid) and YAGNI (You aren't gonna need it) and DRY (Don't repeat yourself) before any other principles. If it seems too convoluted or you don't have clear understanding why... better don't use it than use it in a wrong way. That does not mean people should not strive to learning and understanding better practices. In that context, primary goal of encapsulation is protecting implementation details that can change to avoid subsequent changes in consumer code. When you write your own classes you are the boss, you can decide what is implementation detail and what is not. Of course, you have to be careful about those decisions because you will have to live with them for a long time. When you consume other people's classes you must avoid using things that are not part of public API. Since it is not always possible to hide all implementation details, it is possible that not everything that is publicly accessible is really part of documented public API. Unless public API is clearly documented, sometimes it can be hard to know what is implementation detail, and what is not. Experience can help, but it is hard to give any good general tips on the matter - it all depends on the actual code. And this is where original question came from - what is implementation detail in some code and why is better to use some construct comparing to another. Another thing to keep in mind is that OOP depend on the language. What fits in one, does not fit well in another. In Java encapsulation means having geter and setter methods for everything accessible - because Java does not have properties. If you expose field directly any changes in access logic that has to go through geter or setter will require changes in consumer code - because Java expects parens () when you access method. In Delphi you might as well start with directly exposed field... changing that into property will not change consumer code (unless you add read or write restrictions) and adding geter or setter methods will also have no direct impact on consumer code. Of course, most Delphi developers will use properties instead of directly exposing fields, but this is more of common practice than actual requirement for fields that will be publicly accessible - part of the public API. I could probably go on for days... but I have other things to do... 🙂
  10. Sorry, but you started going off rails saying that you should not use fabc.ToString for displaying integer value as text, thus blowing the whole encapsulation and hiding the implementation thing out of proportion. Now, it is possible that you just used poor example and that you actually tried to say something completely different. I am not trying to shred concepts to pieces, I am just trying to show their usage must be balanced. Abusing the concepts to the point of absurdity is as bad as not using them at all. What better example to show how not everything can be absolutely hidden and protected than to show that strings itself are leaking their implementation details.
  11. I found something... not mine.... actually, the original thoughts on leaky abstractions https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/
  12. No. It was not about leaking strings, rather Delphi strings leaking their implementation details like character size, encoding... Think about going from TP fixed size string implementation to pre-Unicode Delphi string implementation to Unicode Delphi string implementation. I remember writing about it, but don't remember where...
  13. I cannot find it either... I don't think it was a blog post... maybe some post on G+ or somewhere else...
  14. Not all of it. It only hides the integer, but it does not hide how you implemented conversion from integer to string. Also, string type itself leaks its implementation details in Delphi all over the place. You are going extra mile to hide just about everything - without real reasons. Point is, no matter how far you go, you can never hide all implementation details. In one way or another they will leak. It is perfectly acceptable to have integer function or property as part of well defined public API. The whole point of hiding implementation details, and not using them is that by doing so, you can change implementation without changing the public interface and without need to change all the code that relies upon it. That is the purpose of having well defined public API. Hiding inner collection implementation (so you can easily replace plain array with list or some other structure) or some other more complex data is one thing, but hiding basic type like integer is going over the top without actually accomplishing anything. One of the problems when it comes to following good practices like testing, proper OOP design... is that quite often those practices are explained and taught by going into extremes, making them overly complicated and losing original intent - making better, more maintainable code, with less bugs. That blowing things out of proportion, not only makes it harder to understand basic principles behind those practices but it also makes many developers just to drop the whole thing and not use any. It is hard to blame them when they see no point.
  15. Dalija Prasnikar

    Solution(s) for coder with quite poor eyesight

    Pretty good, but not ideal.
  16. Dalija Prasnikar

    Solution(s) for coder with quite poor eyesight

    There is plenty... HP, Dell, ViewSonic... it should not be hard to find suitable one. I am using 1920x1080 at 24" and I have seen 27" 2K monitor simulating HD resolution using 100% font sizes. I could read it across the room.
  17. Dalija Prasnikar

    Solution(s) for coder with quite poor eyesight

    27" monitor with 1920x... resolution and 100% font size might be good enough. There is quite a difference between 24" and 27".
  18. Dalija Prasnikar

    10.3.1 has been released

    Something is not right with your installation. Mine shows 10.3 update 1
  19. Dalija Prasnikar

    10.3.1 has been released

    IDE no longer flickers when you compile/build 😃 Probably the most important fixes and improvements are in iOS platform - including fix for compiling/linking 3rd party libraries against iOS 12 SDK. And then there is a bunch of bug fixes in other areas. So plenty of improvements, just not big ones. Or depends how you look at it, if your code was affected, then even single small fix can be great improvement.
  20. Dalija Prasnikar

    Pitfalls of Anonymous methods and capture

    or MCVE Minimal, Complete, and Verifiable Example
  21. Dalija Prasnikar

    Pitfalls of Anonymous methods and capture

    To be honest, knowing the type of Handler.OnHandle is crucial for understanding the issue. The other implementation details don't matter as much. Broker.AddHandler(Handler.OnHandle); And usually I don't go around and download code examples, just to get to the bottom of some problem. Only under special circumstances - mostly from bugs reported in QP, when having complete test project is crucial for reproducing the issue. The only reason, why I did go and download this example is because I know you. So whether you like it or not, David does have a point.
  22. Dalija Prasnikar

    First!

    Really nice to see you here.
  23. Dalija Prasnikar

    Pitfalls of Anonymous methods and capture

    You are on right track. What happens is something like this: procedure TTest.ConfigLoop; var Handler: THandlerClass; hType: THandlers; hRef: TOnHandle; begin Writeln; Writeln('--- ConfigLoop'); Broker.Clear; for hType in [foo, bar] do begin case hType of foo: Handler := TFoo.Create; bar: Handler := TBar.Create; // wtf: ; end; hRef := Handler.OnHandle; // Capture does no discern between the foo instance and the bar instance Broker.AddHandler(hRef); end; end; and then this bridging assignment from plain method to anonymous method is expanded to hRef := procedure begin Handler.OnHandle(); end; Where before mentioned rules about capturing references (variables) and not values apply.
  24. Dalija Prasnikar

    FYI: Graph showing iOS crashes with recent Delphi versions

    I understand how you feel. Sometimes it is going two steps forward three steps backward. One of the problems with cross-platform development is that not all code is the same. And different principles apply. OS architectures are different and what you can do on one platform, you cannot do on another. I am talking generally, regardless of whether offending code is yours or Embarcadero's. Also mobile platforms change frequently and are also changing rules and behaviors. What worked today, may break tomorrow. This is not related just to Delphi applications but all. I am using Xcode - Swift and Android Studio - Java for mobile development and situation is not much different. The only difference, is that when some policy or behavior changes, you immediately have appropriate tools to implement change. But your code will be broken left and right. You cannot take year old code and make simple recompile - in Swift everything is in a state of flux - language, frameworks, so every time you touch it, it is almost a rewrite. I don't even know what is the proper method for sorting list - its name changed dozen times - from sort to sorted to sort again... what is current one I have no idea - and that is just the simplest example. On Android, Java is the same, but frameworks are changing every week. If you have to support newer versions of OS, you have to use newer frameworks, that also change all the time, are buggy as hell... I know Delphi could and should be better. But, I also painfully know that grass is not greener on the other side. What we can do, is relentlessly report issues to Embarcadero. Not all will be fixed and not all will be fixed as fast as we would like, but Embarcadero is fixing them. Especially, more critical ones.
  25. Dalija Prasnikar

    FYI: Graph showing iOS crashes with recent Delphi versions

    Quick search through Quality Portal didn't reveal any reported issue similar to yours. Can you please file QP report.
×