Why oh why does TFileStream and friends not expose OPEN_ALWAYS?

Why oh why does TFileStream and friends not expose OPEN_ALWAYS?

Why am I forced to use low-level CreateFile just for this rather essential feature?

Comments

  1. Is that a trick question? ;)
    QP it!

    ReplyDelete
  2. Yeah I guess I should have done that ages ago :(

    https://quality.embarcadero.com/browse/RSP-11107

    Let's see what happens.

    ReplyDelete
  3. You use THandleStream passing it the value returned by the call to CreateFile. Kind of sucks I know.

    ReplyDelete
  4. David Heffernan Yeah, especially since you need to manually manage the handle (ie call CloseHandle).

    ReplyDelete
  5. Asbjørn Heid Why? Most cases are covered, especially the common cases. As has been pointed out, the framework provides plenty of "escape valves" to allow for such uses. You could even create your own descendant class that exposes that functionality.

    The question is, why should a product such as this be all things to all people, especially when there are plenty of ways to get the functionality you need?

    ReplyDelete
  6. Allen Bauer​ Because there's a reason I code in Delphi and not assembly. There is no way except perform the CreateFile myself, duplicating a lot of existing code.

    ReplyDelete
  7. Allen Bauer Oh and because it's a trivial thing to implement, it's just mapping an enum to a flag (same on POSIX).

    ReplyDelete
  8. Asbjørn Heid That's a bit of hyperbole, don't you think? My point still stands. The product isn't here to do everything for you. Don't you want some level of control over your own development? I see requests like this all the time, and invariably, they're specialized cases which would be more appropriately be done on a case-by-case basis; not baked down into the product.

    I think we've struck the right balance in this specific case. You don't have to agree and that's OK. We're all going to see things from our own very unique positions. However, as the producer of such a tool, we are in the unique position of being able to aggregate all the various levels of feedback across many portions of the market. I'm just saying that we, too, have a perspective on these issues.

    ReplyDelete
  9. Asbjørn Heid If I had a dollar for every time someone states "oh that's just a trivial thing to do"... Well, I might be able to retire. Too often it is far from trivial. There are testing, maintenance, documentation implications. I've seen plenty of cases where 5 minutes of effort for a developer turned into weeks of extra effort for all the downstream processes (yes, that was somewhat hyperbolic in order to make a point).

    Besides, you just said it was trivial... So it is something that the tool must provide? If it's so trivial, then it seems to follow that you could handle it in your code, no?

    ReplyDelete
  10. Allen Bauer Open up the RTL and I'll send you a pull request, with tests.

    ReplyDelete
  11. Allen Bauer Anyway my point was, this is the kind of stuff I wish Delphi did well. Wrapping the low layers without throwing away important functionality in the process. Instead I'm yet again forced to do the low-level stuff myself.

    ReplyDelete
  12. Asbjørn Heid I have the feeling that you're not really reading my responses or at least not understanding them. I seems to me that all you see is me saying "no" and not really understanding the reasons behind my statements.

    I understand your frustrations here. I get it. For the record, I've not really said "no" either. I'm trying to explain the general approach we take to what is encapsulated and what is not. We also look at a lot of requests and like to understand the reasons behind them and the problems that are being solved.

    Can you imagine the mush of code we'd have if we reacted to every request merely on the specifics of the requests? IOW, we need to understand the motivations and reasoning behind a request. This usually means understanding the problem being solved. We can then look at all the various similar requests and the problems being solved and build a solution that works for more than just that one specifically tailored request.

    I see that I probably should have responded more in that direction instead of how I initially responded. So I'll ask, what is it that you're trying to solve and how would this change be beneficial (aside from not being code you have to write)? You are also free to speculate on how you see it being beneficial to even more than your specific need.

    ReplyDelete
  13. Allen Bauer I want to write a non-buggy version of "if FileExists then Open else Create", with the opened file being accessed by a TFileStream (well THandleStream should be sufficient).

    ReplyDelete
  14. Asbjørn Heid And what if there was no way to do that low-level stuff? Would you even consider Delphi as a tool? Don't you think that is one of its primary strengths? I certainly do. I think we're only disagreeing on what should be low-level and what shouldn't. That's a perfectly valid conversation to have. There will always be some level of tension between those two extremes.

    We, as the tool producer, need to consider the return on investment whenever something is done. Sometimes that return is tangible in the form of more revenue and customers. Sometimes that return is in merely pleasing our customers and further cementing their commitment to their continued use of the tool. I tend to think we're striking a reasonable balance between those two metrics. Sometimes we miss the mark on both counts, and that sucks for everyone.

    ReplyDelete
  15. Asbjørn Heid In this instance, OPEN_ALWAYS is an atomic version of "if FileExists then Open else Create". However, I don't see how this can map to a POSIX version of the same. I see that it can open and truncate or create... not open or create. Maybe I missed something.

    ReplyDelete
  16. I can remember the fiasco of TFile and its broken attempts to call CreateFile. There'd be more time to add useful features if the library devs were better.

    ReplyDelete
  17. David Heffernan I see. How does that comment add to this conversation? Other than the attempt to prove that you're the smartest person the room by disparaging other faceless, nameless developers.

    ReplyDelete
  18. Allen Bauer Delphi is pretty good at keeping me away from the low-level stuff, but it could certainly be better. This is one example IMO. The reason is three-fold:
    - A fairly essential flag if you want non-buggy code is not exposed (and it's hardly a newfangled one, NT4 supported it, likely older).
    - Introducing it myself involves duplicating a lot of RTL code, with extra maintenance burden that is.
    - It's just so frustrating when everything is there except that one little thing you really need.


    I wouldn't be bitching so much about this if it had been easy to modify the RTL units, or if the code (TFileStream) was written in a more extensible manner (say a protected, virtual DoFileCreate method or whatever). Then I'd make the changes and move on. Alas neither is the case, hence my moaning.

    Of course understand Emb has to make money. However as a customer, I reserve the right to complain loudly about my pet issues :)

    ReplyDelete
  19. Asbjørn Heid I presume you've been hit by the implicit file-sytem race condition inherent in reacting to a FileExists() test. I can see this happening in a high-availability, server-base application. This is certainly a valid use case. However, in user-interactive applications, this is a lot less likely to be a problem.

    How would a DoFileCreate virtual help here? You'd still have to map all the various flags and call CreateFile() yourself. This can be done in your own constructor just as easily. Making DoFileCreate merely a platform-specific wrapper around Windows' CreateFile would be one approach. However that too means that the abstractions provided by TFileStream and/or THandleStream are now "leaky".

     If the OPEN_ALWAYS flags had an obvious analog on POSIX platforms, I can see a way forward. However, this may need to remain an exercise left for the user if the abstraction cannot be easily done across all platforms... which is both a blessing and a curse :).

    ReplyDelete
  20. Allen Bauer From what I can see OPEN_ALWAYS does have an obvious analog on POSIX: O_CREAT. Seems you have to specify an additional flag (O_EXCL) to get CREATE_NEW behavior. Though I'll admit I haven't done much POSIX I/O coding.

    http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html

    Anyway, you're right, DoFileCreate would probably not be a brilliant solution. I didn't put much thought into that, and I had forgotten the details of how TFileStream interacts with FileCreate (I'm waiting for Acronis to restore my PC to Win8.1 glory after a miserable Win10 experience).

    ReplyDelete
  21. Asbjørn Heid Aha. Thanks. My Google-fu failed me this time.

    Please enter a request via the Quality Portal. Include as much information about it's purpose why it would be helpful. Also include references to the CreateFile() doc and the POSIX open() doc.

    ReplyDelete
  22. +Allen Library quality is Embarcadero's biggest weakness. I don't blame the nameless developers. I'm sure they are doing the best they can.

    "Too often it is far from trivial. There are testing, maintenance, documentation implications. I've seen plenty of cases where 5 minutes of effort for a developer turned into weeks of extra effort for all the downstream processes (yes, that was somewhat hyperbolic in order to make a point)."

    Getting the quality right from the start will save huge amounts of effort down the line when you have to deal with the consequences of releasing low quality library code.

    ReplyDelete
  23. +Asbjørn You know that this is quite easy to do with THandleStream? It would be nice for file stream to do this but you have all the tools at hand to do it yourself.

    ReplyDelete
  24. David Heffernan At what point will you consider quality as being at the right level? You can look at nearly any product and anecdotally point at some glaring issues and claim lack of quality. I've seen this theme over and over throughout the years, and while we're not perfect, things have improved dramatically. A little bit of acknowledgment of this will help your case immensely. Continuously citing past mistakes (that have since been resolved) as proof of the current state of affairs doesn't really bring anything to the conversation and is perceived (from our perspective) as just complaining for complaint's sake.

    Isn't getting quality right from the start is axiomatic? Do you really think we set out to have low quality? In no way should we justify or excuse lack of quality. In fact, we want to know when things aren't at the right level. This exchange needs to be productive for all involved. We don't have a time-machine to go back and fix the past, we can only focus on the future and those issue that are facing us right now.

    ReplyDelete
  25. David Heffernan I have all the tools at hand to write the entire RTL...

    ReplyDelete
  26. Allen Bauer I had already created an issue, RSP-11107, but I will flesh it out.

    ReplyDelete
  27. David Heffernan Like I said, I moan extra about this because I have to write so much duplicate code for this one flag.

    ReplyDelete
  28. Allen Bauer While we're at it, are QP comments replicated to the internal system automatically, manually or not at all?

    ReplyDelete
  29. Asbjørn Heid I see the internal report too. And I just added your post above regarding the POSIX side... just as your comment was synchronized with the internal report. I guess the external-to-internal synchronization process is working quite well and nearly in real-time.

    I am pleasantly surprised at how well it works.

    ReplyDelete
  30. Allen Bauer That is music to my ears :) Thanks!

    ReplyDelete
  31. +Allen Hard to say when I'd consider the quality sufficient. I don't believe it's there yet. XE8 generic collections are an example of a major recent change that was deficient in quality. It doesn't feel to me that Embarcadero is getting better at this. I can't understand how the testing process could have failed to pick up the quality problem with XE8 generic collections.

    To Emba's credit I do appreciate the effort made to address the long standing bugs and defects. Lots of fixes have been done in the past couple of years.

    But it seems that the more fundamental issues won't get addressed. I'm resigned to Set8087CW and SetMXCSR never being threadsafe. To exceptions changing the FP control state. And so on.

    I submitted a very detailed QC report a couple of years ago on this topic. Nothing changed in the code and now the report appears to have been deleted from QC. In fact, all but 5 of my QC reports have been deleted.

    Ok. Not deleted. But not located by "View reports submitted by me". I found it in an old SO post:

    http://qc.embarcadero.com/wc/qcmain.aspx?d=107411

    Anyway, I've always wondered why Emba won't fix the broken design of floating point control state.

    ReplyDelete
  32. +Allen Are you still there? Do you think I should be congratulating Embarcadero on their handling of my issue.

    "A little bit of acknowledgment of this will help your case immensely."

    It seems to me that you are implying that if I was less openly critical then you be more inclined to address the issue. Are you really suggesting that? I can't believe that you take those factors into account when assessing a report.

    The only sane conclusion I can draw is that you (Emba) don't feel that there is a serious problem here. Which is obviously you prerogative. Perhaps you be good enough to be public about that. Close my report as "as designed" and document that the floating point state handling is not threadsafe by design and that all threads are expected to share the same state for the entire life of the process.

    ReplyDelete

Post a Comment