-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is *explicit* better than implicit? #10
Comments
I can think of no circumstance in which On 16-01-18 04:35 PM, Stefano Zaghi wrote:
Chris MacMackin |
I think 2016-01-18 16:36 GMT+00:00 Chris MacMackin [email protected]:
|
Agreed. So long as they are within a scope in which On 16-01-18 04:41 PM, LadaF wrote:
Chris MacMackin |
@LadaF sure, I agree: in those cases it is unnecessary, but my question was, indeed,
|
There are some tricks for poor man's templates where instead of C macros one can use implicit typing and standard include statement. consider
with "sub_base-inc-1.f90" containing
versus
with "sub_base-inc.f90" containing just the usage of variable |
Very interesting trick @LadaF. Not sure I'd ever use it, but it's interesting nonetheless. I'd go a step beyond making implicit none mandatory at the start of any module or program. I'd also require that it not appear at the start of any module or internal procedure which get it from their host. Programmers learn by example and the takeaway message by having it there is that it must be necessary somehow, and mislead an unaware programmer. |
@LadaF thank you very much, I win my bet, I guessed that I can learn something even by @nncarlson I am sorry, but I completely miss your point. Can you elaborate more on |
@szaghi, If implicit none is present at the start of a module (and I think it should be required) then it applies to the entire module scope and it is not necessary to put it also at the start of the contained procedures, as others have noted. One can go ahead anyway and add implicit none at the start of contained procedures, but it is redundant and unnecessary, and conveys the false idea that it is required. For those reasons I'd require that implicit none not be declared there, but only at the module/program scope. As I said, programmers learn by example. |
I second requiring it not to be declared at the start of internal/module On 16-01-18 09:50 PM, Neil Carlson wrote:
Chris MacMackin |
This could be part of a general rule: do not write code that has no effect. The implicit none scope is an example of where such a rule is not self-evident, for beginners at least. |
@nncarlson and all, sorry, this was so obvious for me that I was confused before reach the second, crucial, argument that @raullaasner clarifies
Wonderful, great zen! Thank you very much. |
@raullaasner is spot on with the general rule. Another example that comes to mind (sorry drifting off-topic) is deallocation of local allocatable variables. Don't bother with explicitly deallocating them before returning to the caller -- it happens automatically. Explicitly deallocating them conveys the false notion to the naive that it is necessary to avoid memory leaks. |
@nncarlson If you want to check the deallocation status and catch any error messages, you would need to do that manually. |
@raullaasner, that's true of course. I'm curious though who actually checks the deallocation status, and have they ever seen a deallocation failure. But don't answer! -- a topic for a different thread when the time is ripe (make a note @szaghi :-) |
The first time I used fortran seriously, I had to introduce a calculation into a larger legacy simulation, and I made some typos. It took me close to a month to figure out why the program was compiling and then returning nonsense. What is the cost of excessive "implicit none" that can be compared with the cost of leaving it out once in error? |
@Tobychev However, when we talk about best practices, I think that the @raullaasner and @nncarlson advice is very important: The our point is avoid to promote false statements, i.e. I agree with you that excessive implicit none has not so high cost, but it is simply not necessary (except for particular scenario, e.g. old-legacy codes with a lot of implicit definitions). See you soon. |
@szaghi For example: mandating that a select statement always have a default clause is a sensible thing even though it might never be reached because the code always chooses one of the earlier branches. Should we then, following the no-dead-code principle, mandate that you should never use a default statement if you are really sure the code will take one of the earlier branches? I would say this is excessive and dangerous advice considering the cost of retaining it (a bit of code that can be optimised away by the compiler) versus the cost of programmer misjudgement ( unexpected behaviour in rare cases ). It is also possible to argue that implicit none should never be included by the strict no-dead-code principle since the same effect can be achieved by use of compiler flags, presuming this option exists in most relevant compilers. I for one always use the "implicit none" compiler flag, but include the statements in program code anyway. I've read arguments that this is good practice because people could copy and build your code without your flags, but honestly its mostly as a tribute to that month I spend trying to get my stupid routine to make sense... Anyway, practice my objection is aimed at the prohibition of implicit none in certain places: I feel this is excessive considering the great cost that can follow from mistakenly leaving it out, and the small cost of its excessive use. I think the style guide should only speak of where it must appear, because there is simply no strong argument against including it excessively. I also think this thread has now derailed from the issue of where implicit can be used, and is now a debate about the exact style of how it should be forbidden. (Sorry that I helped with that). |
@Tobychev great! All interesting arguments!
I agree.
Wonderful! I am taking note, thank you very much!
I partially disagree: I do no like to rely on compiler vendors when a standard syntax is available. I vote for a guideline advising to use
I agree, but I think that we should not talk about prohibition neither about costs: @nncarlson and others suggestions should be viewed (IMO) as an advice that
We are concerning that if we advice to insert Do not worry to drive me far from this topic, I am learning a lot from such a digression, thank you very much! Returning on topic, what do you think about something like the guideline I wrote in my guidelines? Is it comprehensive enough to catch the above suggestions? At least, the compiler-option comment is missing, I guess. See you soon. |
I may be in the minority here, or this opinion may be considered "extreme" by some, but I would actually argue yes to this point. Increasing the size of a codebase and the inclusion of unreachable code is a no-no in my book. Yes it may be seen as defensive coding, but if it's actually impossible to enter that branch of the My philosophy is that you should strive to get 100% test coverage during unit tests, regression tests and integration tests. If you can't devise a way to execute a branch of an This ties in with my software architecture/implementation guiding principal: "Don't build it until you need it." I used to spend a lot of time, and effort thinking about ways that I might want to use a given code in the future, and starting to implement bits and pieces of that to make it "generic" and "future proof." I wasted a lot of time and introduced a lot of bugs. It is much better, IMO to start with a solid object oriented architecture, that is designed to be extensible and generic through use of abstract classes, TBPs etc. but then only build out the concrete implementations that you NEED RIGHT NOW.
I would argue that compiler flags are not standard and therefore, passing the compiler flag as an alternative to
I think the arguments against including it excessively have been enumerated already: Teaching by example that n00bs need to add it everywhere, increasing the code length, and possibly including it where it is not needed, but forgetting it where it is needed. However, I concede that treating this too rigorously is probably excessive. I think it is very important to say something like "you must use This also raises a final question in my mind: submodules I don't know enough about them yet, and have never tried using them, but it is conceivable that numerous submodules may have the ability to be reused and integrated into different parent modules. If this is the case, I think you should be declaring FWIW (pobably not much! 😄 ) these views are solely my personal views and preferences and I respect everyones views on this forum. I just wanted to share my logic, and stimulate further conversation. |
This should be valid for all of us 😄 This is a collaborative effort trying to summarize our views (not only mine, your, of @specific_member). @zbeekman I agree on all. |
@zbeekman !! Demonstration of Fortran 2008 submodules
! J. Overbey - 1 Dec 2009
!! The module and submodules have the following hierarchy:
!!
!! module
!! |
!! |
!! submodule1
!! |
!! |
!! submodule2
!! /|\
!! / | \
!! / | \
!! / | \
!! submodule3 submodule4 submodule5
module module
implicit none
contains ! Empty contains section allowed in Fortran 2008
end module module
submodule (module) submodule1
implicit none
end
submodule (module : submodule1) submodule2
end submodule
submodule (module : submodule2) submodule3
!! Documentation!
end submodule submodule3
submodule (module : submodule2) submodule4
endsubmodule
submodule (module : submodule2) submodule5
endsubmodule submodule3 |
Another case, worth considering, is if one writes generic procedures, and then Fortran |
👍, although personally I have a strong dislike of include statements and have never been satisfied with them as a technique for generic programming. |
I haven’t read much of this dialogue yet, but I’ll briefly add that dead code could lead to confusion subroutine cognitive_dissonance(only_2_possibilities)
https://www.image.ucar.edu/public/TOY/2008/focus2/Presentations/TALKRouson.pdf (sorry for not numbering the slides)
Damian |
Of course, if there are really are only 2 possibilities, then the entire section would be clearer with a logical. And for an integer, do you really want the reader to form a proof that the ‘default’ block cannot be reached. I’d recommend “always” having a default block, but putting it at a low priority. :-) Best practices can be a real time keeper, so prioritize for the cases that are more likely to cause problems. On a slightly related note, what do others think about explicitly including the procedure name in the end clause. E.g., subroutine foo( …) One could omit “FOO” or “SUBROUTINE FOO” and have the same code. In the good old days, I liked the fact that my editor did the autocompletion for me, and for long procedures, I still think the redundancy is a good thing. (TM) However, for short procedures it merely induces a burden to change 2 lines rather than 1 if I decide to rename the procedure. This is actually a relatively common mistake that I encounter when doing simple refactoring. So, I’d stop doing it, but have not been bothered enough to go about determining how to disable this aspect of Emacs - esp. in a manner that allows the redundancy for the occasional long procedure. (I still spend a lot of time editing other people’s legacy code with longer procedures.) Cheers,
Thomas Clune, Ph. D. [email protected] |
My practice is to add the name after the Vlad 2016-01-20 14:56 GMT+00:00 tclune [email protected]:
|
The default clause issue is an interesting one. I tend to agree with @zbeekman here. My policy is to omit it if it is not needed, with one exception. If the intent is that one of the case stanzas is always executed but it is not completely clear from the immediate context that this will be the case, then I do add the default clause with an assertion: case default
ASSERT(.false.)
end select Here ASSERT is part of a simple macro-based DBC system that I use. ASSERT asserts that its argument is true, so the strange idiom ASSERT(.false.) will trigger an error. In this case the default clause serves to document to the reader the intent that one of the case clauses is supposed to be executed. |
To all: wonderful... how many notes I am keeping... @nncarlson what does DBC mean? It is very interesting, Fortran errors handling is a mistery for me, can you elaborate more? |
@szaghi, Design-by-contract. The full-blown concept (which I really don't know) is much more involved than my simple use of it with things like preconditions and postconditions. This is built into some languages. C handles it (if I remember correctly) via macros like I am doing. I've got two macros ASSERT and INSIST. ASSERT(expr) expands to a statement that calls an "abort" procedure if expr is not true, which prints out file and line number, and then halts execution. That is unless the code is compiled with the (boolean) macro NDEBUG defined, in which case ASSERT expands to a Fortran comment. INSIST is just like ASSERT except it is always live. The policy is that these should never be triggered; e.g., they are not for checking user input or errors that could result from bad user input -- proper error checking should be used for that. I've found this to be so incredibly helpful during code development at immediately pinpointing programming errors that would otherwise require hours (or days even) to track down. It also serves as very useful documentation to the reader. For example, if a subroutine takes two array arguments that should be of the same size, I'll do something like subroutine foo (a, b)
integer :: a(:), b(:)
ASSERT(size(a) == size(b)) |
yes I'll add my 👍 for @tclune's ESMF requiring keywords for optional args technique. Makes code more legible if arguments are given sensible names and argument lists are not huge. |
@tclune the ESMF keyword technique is very cool. I'd not seen this before, but I'm sure to use it now. I'd leave the definition of the unused type local and not use a module though; it's just several extra lines which I find preferable to introducing a new module dependency, new file, etc. I wonder if this isn't also a new language feature that could be proposed (if it hasn't already); a special argument list marker (e.g. ':') that indicates all subsequent arguments must use keywords? Off hand I don't see why such arguments must always be optional. |
True, it appears you could force all arguments to use keywords by creating an inaccessible type and using it as the first dummy argument. |
Dear All, I have added a first draft of this guideline. I hope to have added all in topic suggestions, for the off topic ones I have taken a note for other discussions (coming soon). For the implicit templating trick I have added a comment here, but I realized during typing it that I have not completely understood it... please amend it with a more clear example, at least for me 😄 See you soon. |
In the specific case of ESMF and @tclune correct me if I am wrong, the motivation behind this is to ensure future backward-compatibility. In this way, the API can be extended in the future versions while not breaking the procedure calls that were valid for previous versions of the library. |
Yes - that was the ESMF motivation as I understood it at the time. But it can only be used for requiring keywords for optional arguments. The reason is simply that the “Unusable” argument itself must be optional (think about it). And you cannot put non-optional arguments after optional arguments. You could have a non-enforceable policy to always use keywords, but I would generally find that style to be overly verbose. Even modestly sized statements would tend to wrap beyond one line. But if your interfaces support small numbers of reasonably short argument names, I’d have no problem with it. The readers of that code would probably appreciate it.
Thomas Clune, Ph. D. [email protected] |
I wish that slowing down would actually help vendors catch up, but I think there is more than one vendor the has stalled in the sense that they haven’t addd any significant new standards support in in quite a while. One vendor achieved Fortran 2003 compliance roughly 5 years ago and is still missing arguably the biggest Fortran 2008 feature: coarrays. Half a decade should have been enough time to implement the feature. Now amount of slowing down on the committee’s side will address this. Another vendor finished Fortran 2003 compliance roughly 2 years ago and hasn’t added even one significant 2008 feature. In some arenas, this would lead to consolidation in the market, but it seems unlikely, given the various competitive advantages each vendor has on their own hardware (if they make hardware). D |
@tclune are you sure about that? A quick test with ifort and nagfor suggests it possible to have non-optional arguments follow optional arguments (in the procedure declaration). It is true that in a procedure reference non-keyword arguments are invalid after keyword arguments have been encountered, but that is exactly what is desired. |
I see that Zaak and I appear to be twins here of late. I just saw the above post after sending an almost identical message myself. What is needed is for customers with deep pockets to make standards-requirement a contractual obligation for delivering major hardware. If a center buying a $100-million dollar supercomputer start stipulating Fortran 2008 compliance in their request for proposals for major acquisitions, then we would suddenly see Fortran 2008 compliance everywhere. This has happened and has worked on occasion. I suspect it would happen more often if users were louder. The Fortran community is a very quiet community. If any of you receive a user survey from a large supercomputer center, please respond and please make it very clear in the comments the Fortran 2008 compliance is pressing need for your project and tell everyone you know with accounts to do the same. At some point, the centers will have to take notice and the vendors will have to respond. Just for little perspective, the Fortran 2003 standard was published in 2004 and the Fortran 2008 standard was published in 2010! Cray’s compiler has been Fortran 2008 compliant since at least 2014. The fact that no one has caught up with them or done the same thing now more than five years after the standard was published is a crime. Damian |
You are correct. I was typing quickly and rationalizing the answer that I expected. Of course, an optional argument before a non-optional argument is not really optional, is it?
Thomas Clune, Ph. D. [email protected] |
On 1/21/2016 12:29 PM, Damian Rouson wrote:
I would also remark that the development of debugging capability is even |
There is a branch of GDB which can handle at least some of the F90
|
I think that we should face one reality: Fortran is de facto today the language of a rich but niche market. Furthermore, as pointed out above, selling software has become increasingly hard, even for HPC. Paying HP 100 million? No problem. Paying PGI, Allinea and Roguewave 10 million (i.e. 20 person years if it by miracle all went into R&D, realistically more like 5 years)? Suddenly a problem. The only ones who've basically fixed this are Cray, by basically being the Apple of HPC (vertical integration). And indeed their compilers tend to be among the most compliant, at least AFAIK. So my point being: We simply have to live with the fact that 2008 compliance is still way out for some compilers. The question is, whether portability is more important to the best practices proposed here, or whether it is "modernness" of code. I tend to favor portability. It would be interesting to get the other opinions on this. Edit: One more idea on this: How about we add some visual markers to the Guide that displays the compiler compatibility for each recommendation? Maybe format it as a html table with unicode symbols? [cm] = checkmark
|
I think @muellermichel's suggestion of marking recommendations with their compiler compatibility is a very sad, but required necessity. We should make sure we include the version numbers too, in the event that the list doesn't keep pace with compiler releases. I also think that it is important to strike a compromise between portability and "modern-ness" on the one hand I don't think that you should write new code assuming the worst, most antiquated systems should be able to run it; if you did that you'd be stuck writing Fortran 77! On the other hand, some features just aren't supported (even if they claim to be) by compiler vendors, and this can cause a real headache. If only there were a tool that would help translate modern Fortran into something more widely understood by todays compilers, to free us from the tyranny of the slow/crummy implementation of new language features... |
Well, if you want a modern language which can be converted into an older one, there's always Vala, which gets translated to C before being compiled. Not really relevant, but it's a cool project because it is an object-oriented language which can produce (as well as use) libraries written in C. It also has C-like performance, apparently. It would be entirely possible for people to write a similar tool for Fortran, though not enjoyable... I certainly am not nominating myself! |
Portability versus modernness is a very difficult question and I'm not confident there is one reasonable answer that can be clearly be identified as the correct answer (or even the consensus answer) in the abstract (meaning without a funded project with deadlines to drive the decisions). I'll offer that one of the best pieces of advice I ever received was from the review my publisher solicited when I submitted my book proposal. I was planning to use Fortran 95 to emulate OOP in my book. The reviewer commented, "If you really want the book to have lasting value, use the OOP features of Fortran 2003." That was early in 2007 and I didn't know of any compilers that supported the OOP features of 2003 at the time. It took upwards of six months to find out that IBM supported the features and to find IBM compiler test team engineer and Fortran standards committee member Jim Xia to work with me on learning the features and writing a journal article on design patterns in modern Fortran. Arguably that reviewer's one comment had a greater impact on my career than any other single sentence of advice. It is a very large part of why I'm doing what I'm doing today. If we want our work to have lasting value, I suggest we choose modernness over portability, assuming portability is defined by the ability to use a wide range of compilers. Alternatively, if portability is defined by the ability to use a wide range of hardware, I suggest that most of Fortran 2008 and even a goodly chunk of Fortran 2015 can be used on a very wide range of hardware if one installs the current development branch of gfortran. And for many people who would be uncomfortable installing the development branch themselves, I suggest installing OpenCoarrays, which will install gfortran for you if it does not detect gfortran in your path or if the gfortran version in your path is old. (@zbeekman, let's get that next release out the door. ;) ) |
@muellermichel wonderful idea! @zbeekman I agree. @rouson I think that Fortran 2003 is sufficient mature to be considered widely supported, do you agree? I am not stressing all 2003 features and I am not using many 2008 ones, but my feeling is that with Intel, GNU and IBM compilers the way to 2003-modern-ness is feasible (I am facing with some bugs, but workarounds exist). I still think that portability, understood as a synonim of practicality, counts more than modern-ness at the end. For example, I would very very like to try Parametrized Derived Type, but its support is so limited that my portability/practicality considerations stop me to try. P.S. OpenCoarrays rocks! |
Moreover, parallelism is of paramount importance in the multi-core, many-core era. In that regard, coarray Fortran is a game-changer. The power of being able to write code with no reference to external libraries and have that code scale from a dual-core laptop to a 100,000-core supercomputer is just too much too big a deal to ignore. You can do that today with gfortran (and with Cray).
I always find it a bit confusing that people use the word to mean “using the feature with different compilers” rather than “using the feature with different hardware”. In the mainstream, non-technical world, I think most people use the term “portability” to mean moving objects physically from one place to another. It is only in the Fortran world that the unevenness of compiler support has forced us into the is awkward use of the word to mean moving code across compiler space. Most importantly, if we choose this awkward use of the word, then we will make decisions today that will seem outdated next year or the year after. Damian |
Yes, that's how I meant portability. I would actually narrow it down further: Look at the Top 100 list, take out the systems that have been introduced or upgraded in the last, say, 3 years and look at their architecture - what compilers / versions can they support?
Here's where I don't agree: Today we should get ready for hardware architectures with increasing amounts of shared memory parallelism, namely today Tesla cards and Intel MIC, but it could be a number of other architectures further down the road. At least with GPUs we are limited to (a) Cray systems with Cray or PGI compiler or (b) other systems with PGI compiler. Gfortran just isn't an alternative there, and probably won't be for quite some time. |
@muellermichel : OpenCoarrays is actively working on supporting these architectures; the future may be closer than you think! |
@zbeekman : Interesting to know. How soon would you guess can this be ready for production? By that I mean support for all relevant modern GPU features like unified memory, GPUdirect, dynamic parallelism; furthermore support for different storage orders used for different architectures, and last but not least support for at least one usable debugger and profiler, and all that without breaking for large codebases. I've had quite some experience with OpenACC now, which strives for these goals at an IMO more modest level and IMO it is not stable enough for large codebases like, say WRF. The amount of stuff that still breaks between each point release is tremendous. |
😄 I agree, GNU gfortran is my preferred compiler now (again).
Indeed, I would like to be totally unaware of compiler and or hardware: in my Utopia I would like to deal with only Fortran, but as @muellermichel stated above, the reality is more sad.
This is not my case: I use portability often in the contest move the code from one architecture to another. In particular with architecture I mean the available combination of hardware/compiler. In the past I have faced with the impossibility to select my preferred compiler, thus porting the code from my architecture to another was problematic (there were some non standard codes). In my mind, being standard = being portable = being practicable (what an approximation of English I am using... order -10).
Yes, but I think that we coarrays is changing many things in this regards: they are a standard way to exploit the hardware being unaware of the hardware itself. At least, this is my hope. |
@muellermichel, if you're considering using coarray Fortran (CAF) with gfortran on the architectures you mentioned, then I suggest posting to the OpenCoarrays Google Group or emailing us at [email protected] and describing what you'd like to do. I think you have to subscribe to post, but it's a very low-volume list. The most recent message was on 17 December. As @zbeekman, it might not be as far off as you're thinking and there might even be some existing capabilities you could use if you clone the repository. Alessandro has done some encouraging testing on Intel MIC and is working on some support for offloading to NVIDIA. I'm certain there is a long road ahead, but it's likely that more has been done already than you're imagining. If you're talking about non-CAF calculations, then I'm less knowledgeable, but I would then suggest emailing the gfortran mailing list to describe what you want to do. Again, I think there might be more there than is widely known. |
On 1/22/2016 1:00 AM, Chris MacMackin wrote:
GDB's pointer management is present, but incomplete. They have not
|
No way would I put NAG in that category. Their 6.0 compiler is nearly |
On 1/22/2016 8:06 AM, Damian Rouson wrote:
|
I agree.
If the related bugs have been reported via gfortran’s Bugzilla site, then please If organizations pay for a license for commercial compilers, then it’s reasonable To be sure, I have also seen some bug reports languish with gfortran, but Damian |
On 1/22/2016 11:35 AM, Neil Carlson wrote:
|
Thanks for sharing this perspective. I’ve had such a hard time relating to the common Damian |
I feel that there is an almost unanimous agreement on that
implicit none
must be mandatory, but I guess many of you will provide interesting exceptions, soIn the case you disagree, please elaborate your idea.
The text was updated successfully, but these errors were encountered: