www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - A hypothetical question

reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
Say you have an IDE for D (such as Descent), featuring autocompletion,
error highlighting, and any number of other features which require solid
semantic analysis. In the course of performing said analysis (strictly
the non-interactive part), how much sense does it make to attempt to
analyze all conditional blocks?

On the one hand, you have the compiler, which throws conditional blocks
away with little ado. These blocks may be designed to work under
specific version sets which may not be readily gleanable from source.
They may contain complete garbage (e.g. syntax or semantics not valid
for this version of D, but maybe valid for another version). This could
swamp the user with error messages which aren't really valid.

On the other hand, this is an IDE. Any moderately ambitious project is
going to have different versions for different platforms, different
modes of operation, etc. If you have errors in specific versions, you
want to know about them up front. And you don't want autocompletion to
suddenly stop working in part or in full inside odd version statements.

Another point is efficiency. If you have symbols that can resolve to
different types depending on version, it could potentially make semantic
analysis much slower when checking expressions that use those symbols.

The possibilities I see are:
* have the user input a single version set to use when performing
analysis (ape the compiler), and change it whenever he/she/it wants to
work on different versions (bleach!)
* have the user input specific version sets, all of which must be
checked when performing analysis
* run analysis over all version sets
* let the user choose which of these to use

Thoughts?

(And I have no idea what Descent does in this regard. Ary?)
Aug 25 2009
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-25 20:10:44 -0400, Ellery Newcomer 
<ellery-newcomer utulsa.edu> said:

 Thoughts?

In case you're interested, Xcode, Apple's IDE, has to deal with multiple versions all the time. It's typical for Mac developement to build two or four versions of the same executable (PowerPC 32 and/or 64 bit + Intel 32 and/or 64 bit) before merging all four in the same executable file. That's done automatically by Xcode under the hood by compiling each file multiple time for all the targets. So with Xcode you're generally compiling several versions of the same code at one time. Xcode doesn't do a very rigourous semantic analysis: it merly ignores conditionals when it gathers its list of symbol for autocompletion, and it doesn't itself flag errors as you type (it does run the compiler in the background though, and shows errors inline in the source code instantanously when you build). So a similar idea for an IDE like Eclipse/Descent could do is allow you to select one or more sets of compiler flags and combine the result (autocompletion choices + errors) in a single view. Xcode does that only for the architecture. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 25 2009
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Hello Ellery :)

Ellery Newcomer escribió:
 Say you have an IDE for D (such as Descent), featuring autocompletion,
 error highlighting, and any number of other features which require solid
 semantic analysis. In the course of performing said analysis (strictly
 the non-interactive part), how much sense does it make to attempt to
 analyze all conditional blocks?

I think it makes a lot of sense because often when you make a change to one version you want to make the other version kept in-sync, so any quick errors you get because of out of sync changes is good. It also makes sense when renaming a symbol: you want (do you?) all possible versions of a symbol to also be renamed.
 
 On the one hand, you have the compiler, which throws conditional blocks
 away with little ado. These blocks may be designed to work under
 specific version sets which may not be readily gleanable from source.
 They may contain complete garbage (e.g. syntax or semantics not valid

Syntax must be valid in D. I checked this in C# and it's not a requirement. So in this case D is better.
 for this version of D, but maybe valid for another version). This could
 swamp the user with error messages which aren't really valid.
 
 On the other hand, this is an IDE. Any moderately ambitious project is
 going to have different versions for different platforms, different
 modes of operation, etc. If you have errors in specific versions, you
 want to know about them up front. And you don't want autocompletion to
 suddenly stop working in part or in full inside odd version statements.

In Descent autocompletion doesn't work in inactive code (code not reached by the current debug/version conditions). It also appears as grey.
 Another point is efficiency. If you have symbols that can resolve to
 different types depending on version, it could potentially make semantic
 analysis much slower when checking expressions that use those symbols.

I think this isn't a big deal. At least in Descent full semantic analysis is run for the current module: the other modules are partially looked as needed.
 
 The possibilities I see are:
 * have the user input a single version set to use when performing
 analysis (ape the compiler), and change it whenever he/she/it wants to
 work on different versions (bleach!)
 * have the user input specific version sets, all of which must be
 checked when performing analysis
 * run analysis over all version sets
 * let the user choose which of these to use

Descent has the bleach option. :-P
 Thoughts?
 
 (And I have no idea what Descent does in this regard. Ary?)

It's made that way because it's the easiest of the options. Also Visual Studio works exactly like that. I just tried renaming a symbol which has another definition in some other inactive code, and the inactive symbol wasn't renamed. So I thought "If Visual Studio works like that and I never saw anyone complaining, it must be a good choice". But... I think D is very different than C# because conditional declarations are not the common case in C# (at least in all the code I've written in C# I never used them). So it would be nice to check also version branches. The problem is that if you have a file like this: version(Foo) { // Something } version(Bar) { // Something else } You'll have to make semantic analyis for these cases: - !Foo && !Bar - !Foo && Bar - Foo && !Bar - Foo && Bar because each one of those combination is a valid version combination. Also you have to combine that with debug levels (that combination can be reduced by checking if there are debug versions in the affected modules). You might get errors with some combinations because those were not intended to be used together (for example Windows, Unix, etc.) I think we arrived to this conclusion with Robert Fraser. :) On the other hand maybe semantic analysis can be performed with any of those versions. You thihk that can work? Because that'll solve a big problem in Descent that's: if your current version is Windows, all the posix/unix modules in Phobos/Tango give you an error because many things are not defined. The other problem is: version(Unix) { } else { static assert("This module should only be compiled with Unix version"); } You'll get that error in each module that looks like that if Unix version is not set. So... should I try checking each version? I wouldn't know which errors to show (the union? that'll trigger the static assert above; the current version? that brings us to the beginning of this discussion). Also... Descent is still not good at showing exactly the same errors as DMD would give you, and probably will never be like that (partially because some errors are in the back-end and when most of the code was ported we didn't have access to it, partially because it's hard to make it work like DMD when you need to reduce the amount of semantic analysis needed to make the IDE work fast). So the only benefit I would see is getting autocompletion/go-to-definition in inactive code. Finally, no one complained about this, but probably because not many people use Descent. ;-)
Aug 25 2009
parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
Ary Borenszweig wrote:
 Syntax must be valid in D. I checked this in C# and it's not a
 requirement. So in this case D is better.

yeah, sort of. I had this in mind, though: version(D1){ int i; }else version(D2){ mixin("shared int i;"); }
 I think this isn't a big deal. At least in Descent full semantic
 analysis is run for the current module: the other modules are partially
 looked as needed.

Here's what I'm visualizing: Say you have symbols A,B,C. A can be defined one of say four ways by: version(4){ typedef int A; }else version(3){ typedef real A; }else version(2){ typedef FoobarClass A; }else{ typedef FoobarUnion A; } or something of that nature. B and C are the same way (their respective version conditionals are independent, though). Now say you have an expression that contains A, B, and C and you want to deduce its type. you have potentially 64 different types that could result from that depending on which versions you choose. Maybe efficiency isn't a big deal, but combinatorial growth does scare me.
 So it would be nice to check also version branches. The problem is that
 if you have a file like this:
 
 version(Foo) {
   // Something
 }
 
 version(Bar) {
   // Something else
 }
 
 You'll have to make semantic analyis for these cases:
  - !Foo && !Bar
  - !Foo && Bar
  - Foo && !Bar
  - Foo && Bar
 
 because each one of those combination is a valid version combination.
 Also you have to combine that with debug levels (that combination can be
 reduced by checking if there are debug versions in the affected
 modules). You might get errors with some combinations because those were
 not intended to be used together (for example Windows, Unix, etc.)
  I think we arrived to this conclusion with Robert Fraser. :)

My current mode of thinking is that you would treat the version blocks as if they were both there and just return multiple results when symbol lookup could result in something in either one of them and/or in the enclosing scope and handle analysis accordingly. But hmm, there's going to have to be some sort of enforcement for the case when any of those blocks get chopped.
 
 On the other hand maybe semantic analysis can be performed with any of
 those versions. You thihk that can work? Because that'll solve a big
 problem in Descent that's: if your current version is Windows, all the
 posix/unix modules in Phobos/Tango give you an error because many things
 are not defined. The other problem is:
 
 version(Unix) {
 } else {
   static assert("This module should only be compiled with Unix version");
 }

Yuck. I suppose you could treat a lone static assert(false) inside a version block as a hint... ugh more complexity..
 
 You'll get that error in each module that looks like that if Unix
 version is not set.
 
 So... should I try checking each version? I wouldn't know which errors
 to show (the union? that'll trigger the static assert above; the current
 version? that brings us to the beginning of this discussion).
 

Maybe not. I don't know how descent is set up right now. Michel suggested running separate passes for different version sets, which would probably be easiest. Another thought I had was to group errors hierarchically based on version and let the user control which errors should be displayed.
 Also... Descent is still not good at showing exactly the same errors as
 DMD would give you, and probably will never be like that 

Spare me an ulcer and don't try to make it conform. In my view, unless you have access to the guts of the compiler, your ide shouldn't try to mimic it. It should only flag a well specified set of error conditions and leave the rest to be flagged during the actual build. I think if you align yourself too closely with DMD, you're setting yourself up for trouble when other implementations of D come out, which could behave very differently. And then there's all the incorrect and inane behavior inside DMD, which IMO is pointless to duplicate (though maybe difficult to identify)
Aug 25 2009
prev sibling parent Tim Matthews <tim.matthews7 gmail.com> writes:
Ellery Newcomer Wrote:

 Say you have an IDE for D (such as Descent), featuring autocompletion,
 error highlighting, and any number of other features which require solid
 semantic analysis. In the course of performing said analysis (strictly
 the non-interactive part), how much sense does it make to attempt to
 analyze all conditional blocks?
 
 On the one hand, you have the compiler, which throws conditional blocks
 away with little ado. These blocks may be designed to work under
 specific version sets which may not be readily gleanable from source.
 They may contain complete garbage (e.g. syntax or semantics not valid
 for this version of D, but maybe valid for another version). This could
 swamp the user with error messages which aren't really valid.
 
 On the other hand, this is an IDE. Any moderately ambitious project is
 going to have different versions for different platforms, different
 modes of operation, etc. If you have errors in specific versions, you
 want to know about them up front. And you don't want autocompletion to
 suddenly stop working in part or in full inside odd version statements.
 
 Another point is efficiency. If you have symbols that can resolve to
 different types depending on version, it could potentially make semantic
 analysis much slower when checking expressions that use those symbols.
 
 The possibilities I see are:
 * have the user input a single version set to use when performing
 analysis (ape the compiler), and change it whenever he/she/it wants to
 work on different versions (bleach!)
 * have the user input specific version sets, all of which must be
 checked when performing analysis
 * run analysis over all version sets
 * let the user choose which of these to use
 
 Thoughts?
 
 (And I have no idea what Descent does in this regard. Ary?)

IDEs require a lot of parsing code to be of any use eg: in visual studio it often reports false problems with your c++ code but then becomes successful at compiling and developers usually install plugins like visual assist x. Clang is a successful project that identified this problem and wrote a set of independent libraries to be used by ide's, compilers and anything else. In the long run I hope we can have something similar for D.
Aug 25 2009