Jump to content

Dalija Prasnikar

Members
  • Content Count

    1062
  • Joined

  • Last visited

  • Days Won

    91

Posts posted by Dalija Prasnikar


  1. 20 minutes ago, Vincent Parrett said:

    I would suggest that if you want everything synchronous then don't use messaging, there's no point and you are just adding overhead for very little gain.

    Gain with any messaging system is decoupling, so it makes sense to use it even if you make synchronous calls.

     

    But in multithreading scenarios, you need full fledged thread safe system capable of posting messages to a queue. In other words, asynchronous messaging. Anything else is just a crutch that can be used only in most simple scenarios.

    • Like 4

  2. 2 hours ago, Andrea Raimondi said:

    Multithreaded applications - in my view - should be made with appropriate libraries such as OmniThread, because you reap all the benefits of multithreading while keeping (most of) your sanity 😄 

    The problem remains that if you send async messages in a multi-threaded application you very easily end up not knowing how that message came about in the first place because, you know, thread debugging sucks and not just in Delphi.

    Given that a message may be coming from a different threading context, things get wild very quickly. 

    Yes, it can be harder to track from where message originated, but synchronous executing will make your thread wait twiddling thumbs while code runs in the context of the main thread. That is why posting messages is preferred. Of course, everything depends on the particular application and code and whether you can afford performance drop or not.


  3. 48 minutes ago, Anders Melander said:

    Yes I'm aware that it's not recommended and of the limitations. My point was that claiming that it's deprecated is just FUD aimed at driving developers towards alternatives such as SDI.

    You can call it whatever you like, but if the fact that MS didn't bother to update MDI window style to match their latest (now 5 years old) Windows 10 OS does not qualify as being deprecated, then I don't know what deprecated is. Also MS is spreading that FUD for the last 25 years...

    • Like 1

  4. 41 minutes ago, Anders Melander said:

    Deprecated by whom? I don't think I've ever seen that claim backed by a first hand source.

    I think it's a bit like the claim that circulated about Win32 being deprecated which surfaced when .NET was released. Or about GDI when GDI+ was released.

     

    In addition to what @David Heffernan said

     

    https://docs.microsoft.com/en-us/cpp/mfc/sdi-and-mdi?view=msvc-160

     

    Quote

    Under Windows 95 and later, applications are commonly SDI because the operating system has adopted a "document-centered" view.

     


  5. 1 hour ago, Lars Fosdal said:

    I like the KISS rule - what can I say.

    Me, too. 

     

    But complexities often come with additional features. And often simple systems do not have all the needed features, so when you need them, you can either write your own thingy that only has features you need, or you can use existing more complex one that has features you need plus some more.


  6. 4 hours ago, Andrea Raimondi said:

    I read that and I still disagree 😄 

     

    I like System.Messaging because it's synchronous and you need to plan the message flow. I am not saying that yours is a bad solution, all I am saying is that I like synchronous solutions such as Systerm.Messaging better on philosophical  grounds. Async stuff is much harder to debug and will often not return enough on your investment to make up for the added difficulty in debugging and reasoning about things. 

     

    I want to be able to follow things along so that I know that from Step A we go into Step B and not that Step XYZ gets in the middle without any apparent reason 😄 

    That is fine. 

     

    Point is that System.Messaging is not thread safe. If you are writing multi-threaded application and you need to communicate using some messaging system, then System.Messaging will simply not work in such conditions. You can still use it to send messages to the main thread, but you need to synchronize messaging code, which is not always viable solution.

     

    In multithreaded applications, you will need thread safe messaging system that is also capable of posting messages to some message queue.

    • Like 1

  7. 3 hours ago, Darian Miller said:

     

    Congrats!  Are you working on publishing a print version?  

    Not yet, as we have a backlog of other projects that piled up in the meantime. I had COVID and the earthquake hit the region again on December 29. None of this helped my keep my planned schedule. I do plan to release paperback eventually, but can't tell exactly when.

    • Like 1

  8. 15 hours ago, emailx45 said:

    @Dalija Prasnikar

     

    i have a big problem with your book / link...

     

    i dont buyed it and i cannot download it then i can get it for-free?.  :classic_blink::classic_cheerleader:

     

    hug

    Eh? Imagine how people who pay would feel if I start giving it away :classic_smile:

     

    Anyway, if this would be bread and you would be hungry, I'd give you a loaf without thinking twice, but it's not. As much as I'd like to think it is, this book is not really something you can't live without, so... Sorry...

     

    And about hugs... My husband expressed his wish to have a private chat with you... you'd better lay low for a while :classic_smile:

    • Like 2
    • Haha 2

  9. 46 minutes ago, David Heffernan said:

    In this case the lock is needless (with interlocked reference counting). The interesting case has to be where G is modified. But the reference counting is interlocked, and I'm sure it's there for a reason, and I'm sure that I've forgotten what that reason is.

    I don't know if there is some other reason, but one reason is that with interlocked reference count you can freely use reference counted instances of any type (interfaces, dynamic arrays...) in multithreaded environment for read access if all threads have acquired their strong reference before original reference has been written to (cleared or assigned).

     

    In such case you don't need any other more costly locking protection, and you can share same string, so no copying necessary. Clearing such references when they go out of scope is thread safe, because memory deallocation will happen only in case where reference count reached 0. Also getting strong reference from strong reference (variable) held by thread is also thread safe - when I said held by thread it means that no other thread is allowed to write to that variable.

    • Like 2

  10. 49 minutes ago, Kas Ob. said:

    This took too much discussion and i am giving up

    With this I agree...

     

    There is already solution for this bug - triggering reference counting mechanism for const references. Not other gimmick is necessary. I also said why this solution is not viable, because reference counting induces performance penalty. And this is exactly the reason why there is no reference counting trigger for const parameters so that developers have more control over reference counting and to speed up code execution, since in most code passing reference counting instance (regardless of the type) does not require reference counting.

     

    No reference counting is speed optimization.

     

    49 minutes ago, Kas Ob. said:

    1) Literal string could be initialized to +5 ( or any positive value) by the compiler and this will not break anything, RTL doesn't need the part for checking for -1, we can agree on this , right ? if it is 1 before executing any code then it is impossible to reach 0 and trigger exception by returning it to MM, and considering the compiler and RTL are executing the code of accessing the RefCount in constant or not, then this mean inefficiency on both RTL and compiler too, so at least this can be changed for performance.

    Yes, literal string could be initialized to some higher value. But then every time such string would trigger reference counting just like other strings do. But in this case reference counting would be triggered for string literals, and again that would introduce performance penalty for string literals that do not require memory management and reference counting. Comparing some integer value with -1 is inherently faster than increasing/decreasing reference count. 

     

    Your proposal would again defeat the purpose of having -1 as speed optimization. 

     

    49 minutes ago, Kas Ob. said:

    2) If we introduced another field for (lets say) strings, something like LockCount in the strings header, we could have reached the ultimate protection for strings, and here we have this

     

    We already have that. It is called ReferenceCount field in string header. We don't need another number, negative positive or whatever. 

     

    http://docwiki.embarcadero.com/RADStudio/Sydney/en/Internal_Data_Formats_(Delphi)#Long_String_Types

     

    So your idea with negative flag would not work at all, but even if it would that would also require locking operation on reference count field and same performance penalty. It would be simpler to just trigger reference counting instead.

     

    Your idea with additional field (if I understood that correctly) would now mean we would have to do locking on two numbers instead of one. Again even more performance penalty. 

     

    If we want to pay price in performance penalty, then we could just have compiler to omit all speed optimizations and be done with it. And again I think I explained well enough why this will not happen. Not everyone is willing to sacrifice speed because once in a blue moon some developers might shoot themselves in the foot.


  11. 6 hours ago, Kas Ob. said:

    The RTL is built on preventing the transition from -1 to 0 in case with strings, so why not exploit/use this to protect runtime vars, also why to stop at -1, is there a law prevent using using such usage ? is it wikipedia or unspoken rules of Pascal.

     

    Again, -1 is used JUST for string literals. You know when you write s := '123', then '123' is string literal and it is not dynamically allocated and its memory does not have to be managed. That is why there is optimization in RTL JUST for string literals that skips reference counting for them. -1 tells means you are dealing with string literal. You cannot use that value for any dynamically allocated data (strings).

     


  12. 6 minutes ago, balabuev said:

     

    I knew that you'll say this :classic_smile:.

     

    With Pointer type I just wanted to highlight the fact that its values have no associated second part (like heap chars data in strings). In definition from Wikipedia this mising second part is called - "actual value".

     

    Only nil pointer does not have any associated data. When you put some address in pointer you have associated it with some data that is not directly stored in variable itself. 

    Since main purpose of pointer types is storing address to something, so if you treat that address as actual value, then you can say that raw pointers are value types. There is some ambiguity here, sure.

     

    In case of other reference types, you are definitely not interested in address as value, but content (value) in associated second part and that is what makes strings, interfaces, objects, dynamic arrays reference types.


  13. 5 minutes ago, balabuev said:

    Also, @Dalija Prasnikar, just for fun, how you define for yourself Pointer type? Is it a value type or a reference type?

     

    Pointer is a reference type. 

     

    But if you are bisecting reference types, then reference part (the immediate value stored in variable) has value type semantics. In other words when you assign one pointer to another you are creating copy of a stored value in that variable alone (reference part), just like when you are assigning one integer to another.

     

    If that pointer is not nil - then assigning one pointer to another will still point to the same data location, while pointer itself will have two distinct copies at that time.

     

    That also answers the first part of your question. 


  14. 25 minutes ago, balabuev said:

     

    I want to kindly remeber that the topic is not exclusively about strings...

    
    procedure TForm11.Button1Click(Sender: TObject);
    type
     TFoo = record
       X:       Integer;
       BigData: array[0..15] of Integer;
     end;
    
    var
      s1: TFoo;
    
      procedure Test(const Value: TFoo);
      begin
        s1.X := 9;
        ShowMessage(Value.X.ToString);
      end;
    
    begin
      s1.X := 7;
      Test(s1);
    end;

     

    It works as expected because TFoo is record and records are value types. That means two things, first there is no additional memory management (heap) involved. s1 holds complete content of record on stack without indirections. Next because size of record does not fit into register and Value is passed as const compiler optimization kicks in and passes reference to s1 and not copy. In other words generated code is the same as it would be if you used var parameter. 

     

    If you change declaration of TFoo and make it smaller, you would get different result, because Value would now contain independent copy of the data.

     

     TFoo = record
       X: byte;
       Y: byte;
     end;

    If you change declaration of Test to 

     

    procedure Test(const [ref] Value: TFoo);

    Then regardless of TFoo size it would be always passed as reference (pointer) to the original data, and you would not have two copies.


  15. 48 minutes ago, Kas Ob. said:

    Constant strings since ages does have -1 as reference counting, generated by the compiler by default, hence current RTL you are talking about is built on top of that.

    That is because string literals don't require managing memory as they are part of the executable and are stored in data segment. 

    Their reference count of -1 is just flag used for optimization and omitting reference counting that makes no sense for general reference counting mechanism.


  16. 8 minutes ago, balabuev said:

    You did not understood my point. I guess we both understand that in Swift as in most other languages strings are implemented as pointer to heap allocated memory. As well, as dictionaries. But, nevertheless they call them value types.

     

    Because the value type notion is more general, than you think.

     

    I answered before thinking... so you got me :classic_biggrin:

     

    But, real answer is more complicated. Technically, memory representation in Swift allows both variants depending on the size of data (content). So until you discuss actual code, there is not way of telling how will inner representation work. It may be value and it may be reference. 

     

    In Swift value types and reference types in terms of Swift documentation also means all value types in Swift imply copy on assignment semantic, so for Swift developers that classification carries more weight than actual underlying representation - which again depends on the actual content.

     

    Also Swift compiler has(d) bugs around handling "value types" that are not really value types, but rather reference types in terms of Wikipedia definition, that would cause memory leaks under certain conditions (and other issues). I am saying bugs, because some of those I know about were actual bugs, I am not in position to say whether some of those bugs are just "as designed" behavior similar to Delphi const string parameter behavior. I am not that deeply involved with Swift and I am not familiar with all its internals, that also change every five minutes as Swift involves.

     

    Just like Delphi strings, Swift "fake" value types can suffer from some problems cause by the fact that they don't occupy single location in memory.

    • Like 1

  17. 12 minutes ago, Kas Ob. said:

    Lets establish few things and facts first

     

    The only fact there is is that reference counting does not work like that. And it could not work with any bit flipping. Bit flipping does not solve anything. 

    20 minutes ago, Kas Ob. said:

    What is perplexing me is your insistence that this can't be fixed or even merely the idea it can be fix is a blasphemy,  why ?! technology and science didn't evolve by refusing new ideas crazy or not.

    It is not a blasphemy, it is simply not a working solution. Again, I am not against discussing potential solutions to anything, nor how can something be improved, but when your initial understanding is flawed, there are just too many things that I would have to convince you about. 


  18. 1 minute ago, balabuev said:

    In Swift, Array, String, and Dictionary are all value types.

    Period. :classic_tongue:

     

    I know. And in Delphi all those types are reference types. In Java all those types are also reference types.

     

    Again, definition of value type and reference type does not imply which types in particular language belong to particular category. 

     

    1 minute ago, balabuev said:

    Next:

    No, let's quote again two things: 

     

    - First, is a qualifying condition of the value type from Wikipedia: [a type is a value type, if: ] A value of value type is the actual value.

    - Second, your own words: Value of the string is sequence of characters.

    Value of the string content, not string variable. By your definition all types would be value types. 

    I also quoted Delphi documentation that clearly states value of string variable itself is pointer to actual string data. QED.


  19. 20 hours ago, Kas Ob. said:

    Would you please entertain the idea of fix a hypothetical fix ?

     

    Lets take Interfaces this time for Dalija preference, so we have IntfCopy and IntfClear are the ones responsible to manage and call AddRef and Release, also lets imagine a caller function negated the reference count for const interface parameter before the calling and here we didn't lose the count we just marked it negative to signal it as protected, now we can have IntfCopy and IntfClear to raise an exception, this can be build as assertion in debug build and this behaviour removed form the release if that is not OK, but i think it can thought to work, the idea is to use the signal bit in RefCount as boolean to protected the value form freeing or overwriting, the same principle can work with strings, the compiler will be the one responsible to flick that bit before passing a variable as const and flick it back.

     

    Can this be a seed for a fix ? or just extra check just like overflow and overrun checks ? or am i just lost in stupidity ?

     

    It is called reference counting not bit flipping for a reason.  There is no negative reference count. Any reference counted instance is destroyed when reference count reaches zero. 

     

    Point of reference counting is that reference count is increased a points where instance (string, object, ...) gets additional reference - if you assign it to another variable, but also when you pass it as parameter. Most of the time passing parameters does not require increasing reference count, but compiler is not capable of analyzing whether this is required or not. This is why programmer must decide whether or not reference count trigger is required for some parameter or not, depending on the code within the procedure. If you want to skip unnecessary reference counting then you should mark parameter as const, if you need reference counting trigger then you don't. 

     

    The only possible fix (the one Marco implied when he said that compiler will not change) would be that const parameter ALWAYS trigger reference counting. Since whole point of const when managed types are concerned is to prevent unnecessary reference counting and performance penalty, obviously that kind of fix would make no sense at all.

×