Bugs: Browse | Submit New | Admin

## [#13026] File::SEPARATOR should be "\\" on windows

Date:
2007-08-13 17:14
Priority:
3
Submitted By:
Scott Jacobsen (jacobsenscott)
Assigned To:
Shyouhei Urabe (shyouhei)
Category:
Language / Runtime / Core Libraries
State:
Open
Platform:

Summary:
File::SEPARATOR should be "\\" on windows

 Detailed description I've just hit another situation (passing a file name to a legacy com object) where a ruby program fails to work properly on windows because of this File::SEPARATOR error (breaking File::join). Sure, sometimes "/" works on windows, but "\\" works more often (always?). Python, Java, and C# all you "\\" for the separator on Windows. They can't all be wrong.

 Message Date: 2007-08-15 02:27 Sender: Shyouhei Urabe Talking about python, >>> import sys >>> sys.version_info (2, 5, 1, 'final', 0) >>> import os.path >>> os.path.join("C:\\foo", "D:bar") 'C:\\foo\\D:bar' is this really what you want? ---- Anyway, Ruby has a globing idiom Dir.glob(File.join(variable, '*')) and Dir.glob uses '\\' as the escape character. Which means if we use '\\' as path separator, that glob wouldn't work as the programmer expected. This idiom is so widely used (200+ hit on Google Code Search today), makes it almost impossible to change. Date: 2007-08-15 02:00 Sender: Nobuyoshi Nakada File.join('C:', 'foo') is still undefined behavior and the discussion has not finished yet. It is another story. Date: 2007-08-14 22:56 Sender: Scott Jacobsen It is true that File.join ('C:', 'foo') is a more complex case. The correct result of that operation should be "c:foo", so you have identified another bug in File::join. C:foo means the subdir "foo" of the cwd on C:. That is different than c:\foo. Both .Net and Python handle this pitfall correctly. So does the "Scripting.FileSystemObject" com object that has been around for ever: irb(main):004:0> require "win32ole" => true irb(main):005:0> x = WIN32OLE.new('Scripting.FileSystemObject' ) => # irb(main):006:0> x.BuildPath("c:", "foo") => "c:foo" irb(main):008:0> x.BuildPath("foo", "bar") => "foo\\bar" irb(main):010:0> x.BuildPath("c:\\", "bar") => "c:\\bar" Anyway, the complexity of this one off case is unrelated to this bug - the path separator on windows is a \ no matter what File.join('c:', 'foo') resolves to, either c:foo (the correct one, but nobody knows that anyway) or c:\foo (the incorrect one). Path separators are defined by the OS, not a programming language. I still haven't seen any reason to reject this bug. Here are the main points: 1. The path separator on windows is \. This is simple fact. 2. The 'require' function could easily be modified to allow / on any platform. 3. File.join is broken because it uses the File::SEPARATOR constant. Thus if you write ruby code on windows you must write your own join function, or do the ugly gsub(/\//,"\\") trick to the result of the File::join call. 4. Defining a constant File::SEPARATOR that resolves to / on all platforms is surprising to the user. It serves no purpose. Date: 2007-08-14 21:48 Sender: Shyouhei Urabe File.join on DOS-ish platforms are not that simple as you say.... tell me what's the right answer on File.join('C:', 'foo')? Both 'C:\foo' and 'C:.\foo' can be thought of, and they point absolutely different paths. I doubt your "worth using" languages handle such pitfalls well. # FYI in current implementation File.join('C:', 'foo') # returns 'C:/foo'. And sorry for my missing your need for technical explanations. Date: 2007-08-14 16:28 Sender: Scott Jacobsen Nearly every library for every programming language (or every language worth using anyway) provide some sort of constant that represents the path separator on the platform the code is running on. There is a very good reason for this. It allows you to easily write platform independent code. These libraries also supply some function just like File::join that joins path components together in a platform independent manner. ruby provides neither, but pretends to (thus fooling the new ruby programmer) by defining File::SEPARATOR and File::join that only operate correctly on Unix type file systems. In ruby, what is the _purpose_ of File::SEPARATOR? Indeed, there is no reason to have a File::SEPARATOR constant defined _if_ ruby defines all path separators to be "/" on every platform. After all, typing File::SEPARATOR is 1500% longer than typing /. Because File::SEPARATOR and File::join do _not_ operate in a platform independent manner whenever I write ruby code I need to think "Will I ever be passing this string to a legacy library on Windows? If so I must do this: File.join("path", "to", "file").gsub(/\//, "\\") otherwise it is OK to just do this: File.join("path", "to", "file") Anyway, I was hoping there was some deep technical reason for this bug, not "it made it slightly easier to write the 'require' function. All other uses of file paths be damned." It would be trivial provide a proper File::SEPARATOR and File::join _and_ to implement the 'require' function such that on any platform you could specify the path to a library using "/". Everyone wins. Date: 2007-08-14 06:59 Sender: Shyouhei Urabe Far better than my example of course, but your code is still 73% longer than the good old "require 'test/unit'". If we use platform-specific file separator, we have to insist all programmers to pay that 73% penalty every time they require a library. Do you think it's worth we pay that cost? Date: 2007-08-14 02:07 Sender: Scott Jacobsen That is ridiculous. require File.join('test','unit') is not. Date: 2007-08-14 01:33 Sender: Shyouhei Urabe We intensionally use '/' even on windows. If not, you cannot even simply require: require 'test/unit' but you have to write: case RUBY_PLARFORM when /cygwin|mswin32/ require 'test\\unit' when /macintosh/ require 'test:unit' else require 'test/unit' end This is ridiculous.