views:

596

answers:

12

I just wrote this method:

private String getNameOfFileFrom(String path)
{
 int indexOfLastSeparator = path.lastIndexOf('/');
 if (indexOfLastSeparator > -1)
 {
  return path.substring(indexOfLastSeparator + 1);
 }
 else
 {
  return path;
 }
}

The line that bothers me is:

return path.substring(indexOfLastSeparator + 1);

Is that a bad practice to modify the expression inline like that? Suggestions on how to refactor to increase readability would be most welcome.

----Edit---- OK update after comments. Thanks everyone for answering :) I am not looking to actually change the the value of the variable at all just the expression it is used it.

Another posted suggested I could break out that part of the expression as in the second code snippet below. Better/worse/no difference? :) I am starting to suspect I am being overly cautios here.

return path.substring(indexOfLastSeparator + 1);

or

int indexOfFirstCharInFileName = indexOfLastSeparator + 1;
return path.substring(indexOfFirstCharInFileName);
+5  A: 

In this case, you can just do:

private String getNameOfFileFrom(String path)
{
        return path.substring(path.lastIndexOf('/') + 1);
}

At least, in both Java and .NET, x.substring(0) will return an equal string. In Java it will return the same reference - not sure about .NET.

In general though, there are plenty of times where it makes sense to add or subtract one. I don't really think it's a code smell.

Jon Skeet
A: 

If you're using .NET look at System.Io.Path.Combine(string,string) which is using to combine 2 strings without checking and/or removing terminating slashes

Or you can use string.Remove(string.LastIndexOf("/"));

abatishchev
If the second part of the path is rooted ("\this\path\is\rooted"), Combine behaves in ways you won't normally expect.
Will
+7  A: 

I don't see why that would be a bad practice. Maybe you can increase the variable name before that line and use it with the new value.

But besides that I don't see a problem

Megacan
+2  A: 

I don't have a problem with what you're doing there, but I think you could use a comment to make it absolutely clear that you're looking for the last / and taking the rest of the string after that position.

Stephen Newman
A: 

you are not modifying the variable there.

To do that would be

 return path.substring(indexOfLastSeparator++);

or

 return path.substring(++indexOfLastSeparator);
John Nolan
And of those options, only the second one would provide the result you want (post-increment operator would return the original variable).
Phill Sacre
that's right Phill.
John Nolan
Sorry I am not trying to mydify the variable, only the expression
willcodejavaforfood
+1  A: 

As long as it is easy to read and understand the code, i don't see any problem with this technique. It might actually become less readable if you were to, say, increment the variable in an extra line.

mafutrct
+1  A: 

You don’t modify the variable itself, you only modify the expression. And that’s completely okay, especially in this case as you want your new string to begin at the character after the position of the last separator.

Bombe
I probably could have improved the wording of my heading for my problem
willcodejavaforfood
Probably. Anyway, I don’t think that code smells. It makes the intention pretty clear and that is almost never wrong. :)
Bombe
+3  A: 

If you want to go the whole way, I would do something like this:

    int indexOfLastSeparator = path.lastIndexOf('/');
    if (indexOfLastSeparator > -1)
    {
            int indexOfFirstCharInFilename = indexOfLastSeparator + 1;
            return path.substring(indexOfFirstCharInFilename);
    }
    else
    {
            return path;
    }

This is not yet with good performance, since a new variable is created, but it's highly readable in the way I think you expect it.

Personally I would prefer something like John Nolan suggested:

return path.substring(++indexOfLastSeparator);

It's not that chatty like you want it, but even a programming beginner gets the idea if he read the description of the substring method.

edit: Be aware, the use of "/" in the check of the path is not platform-independent. Use a lib function to get the system-dependent seperator if you're code shall be run on different platforms.

bitschnau
I don't really think the performance is much of an issue here. The optimizer is likely to optimize the variable out. But I would argue whether this is more readable in the case the OP posts. There is such thing as code being overly verbose.
Jason Baker
"return path.substring(++indexOfLastSeparator);" - Also, I'd recommend against this line. It *doesn't* do the same thing as what the OP posted. In this case, it wouldn't matter. But if the OP were to modify the code to use that var later on, they could have some hard to debug errors.
Jason Baker
indexOfFirstcharInFileName is sort of what I was thinking is well, but it does seem to take the whole thing a bit too far though doesn't it? Good point about the method name as well.
willcodejavaforfood
@Jason Baker: You are right. The compiler run shoudl optimize this variable, the impact on the performance should not be to drastic.@willcodejavaforfood: I also think, this goes to far, since an increment of an int should understood, and the method "substring" has to be understood anyway.
bitschnau
Use the framework's classes and methods (i.e. Java / .NET / etc.) to get the file name from the path since those will have a platform independent implementation usually, better bug checkings and performance.
Andrei Rinea
I don't think that increases readability - there are just that many more characters to read and try to figure out what they mean (and indexOfFirstCharInFileName is a bit verbose for my taste). I'd rather just add a brief comment explaining why the +1.
Peter
+2  A: 

Actually in .net you should probably use Path.GetFilename(); instead.

Neil Barnwell
Fair enough, besides the point though :)
willcodejavaforfood
A: 

It IS in GDI+ or drawing code.

Sometimes an underlying issue causes something to be off by a pixel or so and at this point you have two choices.

  • Fix the underlying issue
  • Make all further operations use this crappy +1 or -1 offset.

If the latter is chosen this code smell will be littered across the code.

Quibblesome
+2  A: 

There are two reasons to prefer writing a constant over a magic number:

  1. If the value changes, refactoring can be a nightmare when using a magic number
  2. Magic numbers decrease readability.

If you're sure that neither of these are an issue, I say go for it. In the case of the code you give as an example, I think that:

  1. The offset of the path from the last separator is unlikely to change and
  2. It's not terribly difficult to tell what's going on.

So I say that this is a valid use of a magic number. However, I would also point out that you do have to worry about these two issues more often than you don't, so when in doubt, use a constant.

Jason Baker
However, 1 isn't a magic number. You won't, under any circumstances I can see, have to change the 1 to a 3 or 45, or any other number. Remember the only only numbers allowed in code are 0, 1, and possibly 2.
Kibbee
That's what I was getting at. I was attempting to make the issue less a rule (you can only use 0, 1, and maybe 2) and more a cost/benefit analysis (you can use a literal, but x will happen). In my opinion, rules are less important than the reasoning behind those rules.
Jason Baker
A: 

In Java path.substring(n) does not modify path, or even the String object referenced by path.

Darron
What does that have to do with the question?
Michael Myers