www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Declaring run time variables

reply "splatterdash" <toa.konuva yahoo.com> writes:
Hello everyone,

I'm trying to write a command-line application that can detect 
whether the input file is gzipped or not. Sounds simple enough, 
but I can't seem to do it properly in D (this is my first foray 
to the language).

After checking whether the file is gzipped or not, I try to 
create a new instance of a class that is basically an InputRange 
returning each line of the input file:

```
File f = File("input_file")
// detect gzip ...
if (isGzip)
     auto fileIter = new MyFileReader!GzipIterator(f)
else
     auto fileIter = new MyFileReader!NormalIterator(f)

foreach(string line; fileIter) {
// do things
}
```

However I always get the compiler error `undefined identifier 
lineIter`.

Now, my questions are:

1. What is causing the error? Is this caused by the compiler not 
being able to figure out what fileIter is at compile time?

2. I realize the current way of creating file handles may not be 
the best way to handle gzipped or non-gzipped file. Is there a 
better way to detect and create such file handles based on run 
time values?

Thanks in advance :).
Aug 04 2014
parent reply "anonymous" <anonymous example.com> writes:
On Monday, 4 August 2014 at 22:00:18 UTC, splatterdash wrote:
 ```
 File f = File("input_file")
 // detect gzip ...
 if (isGzip)
{
     auto fileIter = new MyFileReader!GzipIterator(f)
}
 else
{
     auto fileIter = new MyFileReader!NormalIterator(f)
}
 foreach(string line; fileIter) {
 // do things
 }
 ```
(Added braces for clarity.)
 However I always get the compiler error `undefined identifier 
 lineIter`.
You have two independent variables called fileIter. Both are only available in their respective scopes. Declare the variable before the `if` to get one variable with a wider scope: SomeCommonBaseTypeOfThoseMyFileReaderVariants fileIter; if (isGzip) fileIter = new MyFileReader!GzipIterator(f); else fileIter = new MyFileReader!NormalIterator(f);
Aug 04 2014
parent reply "splatterdash" <toa.konuva yahoo.com> writes:
On Monday, 4 August 2014 at 22:09:49 UTC, anonymous wrote:
 On Monday, 4 August 2014 at 22:00:18 UTC, splatterdash wrote:
 ```
 File f = File("input_file")
 // detect gzip ...
 if (isGzip)
{
    auto fileIter = new MyFileReader!GzipIterator(f)
}
 else
{
    auto fileIter = new MyFileReader!NormalIterator(f)
}
 foreach(string line; fileIter) {
 // do things
 }
 ```
(Added braces for clarity.)
 However I always get the compiler error `undefined identifier 
 lineIter`.
You have two independent variables called fileIter. Both are only available in their respective scopes. Declare the variable before the `if` to get one variable with a wider scope: SomeCommonBaseTypeOfThoseMyFileReaderVariants fileIter; if (isGzip) fileIter = new MyFileReader!GzipIterator(f); else fileIter = new MyFileReader!NormalIterator(f);
Indeed I do. I'm not sure which type I should use for the common base type, though. MyFileReader is a templated class, so using it plainly did not work. I also tried `InputRange!string` to no avail despite `MyFileReader` implementing the three InputRange requirement (popFront(), front, and empty). Any ideas on what I should as the class?
Aug 04 2014
parent reply "anonymous" <anonymous example.com> writes:
On Monday, 4 August 2014 at 22:18:24 UTC, splatterdash wrote:
 Indeed I do. I'm not sure which type I should use for the 
 common base type, though. MyFileReader is a templated class, so 
 using it plainly did not work. I also tried `InputRange!string` 
 to no avail despite `MyFileReader` implementing the three 
 InputRange requirement (popFront(), front, and empty).

 Any ideas on what I should as the class?
Let MyFileReader implement an interface that has the operations you need. That interface can be std.range.InputRange!string, or you can define your own. Note that a type is an input range when it has the input range primitives (front, popFront, empty), but it's only a std.range.InputRange!T when it implements the interface in the OOP sense: class C : InputRange!E {...}. Phobos generally doesn't use InputRange, but templatizes everything. You can go that way, too, and move the foreach loop to a templated function: void main() { File f = File("input_file") // detect gzip ... if (isGzip) doThings(new MyFileReader!GzipIterator(f)); else doThings(new MyFileReader!NormalIterator(f)); } void doThings(I)(I fileIter) { foreach(string line; fileIter) { // do things } }
Aug 04 2014
parent "splatterdash" <toa.konuva yahoo.com> writes:
On Monday, 4 August 2014 at 22:45:15 UTC, anonymous wrote:
 On Monday, 4 August 2014 at 22:18:24 UTC, splatterdash wrote:
 Indeed I do. I'm not sure which type I should use for the 
 common base type, though. MyFileReader is a templated class, 
 so using it plainly did not work. I also tried 
 `InputRange!string` to no avail despite `MyFileReader` 
 implementing the three InputRange requirement (popFront(), 
 front, and empty).

 Any ideas on what I should as the class?
Let MyFileReader implement an interface that has the operations you need. That interface can be std.range.InputRange!string, or you can define your own. Note that a type is an input range when it has the input range primitives (front, popFront, empty), but it's only a std.range.InputRange!T when it implements the interface in the OOP sense: class C : InputRange!E {...}. Phobos generally doesn't use InputRange, but templatizes everything. You can go that way, too, and move the foreach loop to a templated function: void main() { File f = File("input_file") // detect gzip ... if (isGzip) doThings(new MyFileReader!GzipIterator(f)); else doThings(new MyFileReader!NormalIterator(f)); } void doThings(I)(I fileIter) { foreach(string line; fileIter) { // do things } }
That does it, thanks :)!
Aug 05 2014