Library proposal: Add System.Info.isWindows

Hi See bug: http://hackage.haskell.org/trac/ghc/ticket/1590 Currently the recognised way to test if your application is being run on Windows is: import System.Info .... = os == "mingw" This is wrong on so many levels! # The return result of os is NOT an operating system # The result mingw does not imply that mingw is installed # String comparisons are not very safe, a typo stops this working # In GHC this comparison will take place at runtime, even though its a constant Since nearly all uses of System.Info.os are to check if the operating system is Windows, adding an explicit isWindows function would simplify things. Proposal: Add System.Info.isWindows :: Bool This value should return True on all Windows systems (Win 1.0 ... Vista), and False on all other systems. Thanks Neil

Hello Neil, Monday, August 6, 2007, 2:26:56 PM, you wrote:
Proposal:
Add System.Info.isWindows :: Bool
This value should return True on all Windows systems (Win 1.0 ... Vista), and False on all other systems.
important question - what it should return on cygwin (and win32-emulating environments on unix if such ones exist) may be [another] good candidate will be a function that returns API? win32/win64/posix/... -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On Mon, 2007-08-06 at 11:26 +0100, Neil Mitchell wrote:
Proposal:
Add System.Info.isWindows :: Bool
This value should return True on all Windows systems (Win 1.0 ... Vista), and False on all other systems.
How about something slightly more general but still not quite so free form as the current System.Info.os :: String. Ian just added something to Cabal for it's own internal use to clean up the use of os-specific #cppery and use of System.Info.os which seems reasonable to me: data OS = Linux | Windows Windows | ... etc | Other String data Windows = MingW os :: OS So it's easy to pattern match on it and it gives us the ability to be more or less specific. For example in the windows case we could distinguish the environment, native vs mingw vs cygwin. That generalises isWindows and means we don't need isLinux, isOSX etc etc. Or if people really want those they can define them in terms of the above. So I suggest this (or something like it) as an alternative. While we're at it, discussing System.Info I think there are several more useful things we could add there, like exeExtension and probably several more. I seem to recall someone proposed a reasonable list on this mailing list some time ago, not just obj and dllExtension but a slightly wider rang of things. I can't seem to find it right now, does anyone else remember? Duncan

Hi
important question - what it should return on cygwin (and win32-emulating environments on unix if such ones exist)
Very good question. I guess we should return the host operating system - i.e. Windows on Windows, and Unix on Unix. The emulation is generally for programs that aren't cross compatible, if you've taken the time to figure out what OS you are really on, you can probably be compatible to it.
How about something slightly more general but still not quite so free form as the current System.Info.os :: String.
Ian just added something to Cabal for it's own internal use to clean up the use of os-specific #cppery and use of System.Info.os which seems reasonable to me:
data OS = Linux | Windows Windows | ... etc | Other String data Windows = MingW
Since when did GNU build Windows operating systems? You can add System.Info.libraries :: [Libary], and make MingW a library, but if you have a Windows enumeration it really should be for a list of Windows operating systems.
So it's easy to pattern match on it and it gives us the ability to be more or less specific. For example in the windows case we could distinguish the environment, native vs mingw vs cygwin.
That generalises isWindows and means we don't need isLinux, isOSX etc etc. Or if people really want those they can define them in terms of the above.
I still propose isWindows. Checking "is this operating system windows" is the most common thing to do with System.Info.os, so should be easily accessible and foolproof. I would be perfectly happy to have something else as well, and implement isWindows on top of it.
While we're at it, discussing System.Info I think there are several more useful things we could add there, like exeExtension and probably several more. I seem to recall someone proposed a reasonable list on this mailing list some time ago, not just obj and dllExtension but a slightly wider rang of things. I can't seem to find it right now, does anyone else remember?
I believe Dimitry proposed them about 3 weeks ago. There are lots of things that could go in System.Info, and I agree more should be moved along. Thanks Neil

Hello Neil, Monday, August 6, 2007, 4:36:54 PM, you wrote:
important question - what it should return on cygwin (and win32-emulating environments on unix if such ones exist)
Very good question. I guess we should return the host operating system - i.e. Windows on Windows, and Unix on Unix. The emulation is generally for programs that aren't cross compatible, if you've taken the time to figure out what OS you are really on, you can probably be compatible to it.
i think it's better to ask people which has cygwin experience overall, i agree with you - it will be great to add isWindows now. details of its behavior may be outlined based on further experience (i bet that there are no cygwin haskell developers at this moment). my only anxiety that it should be put outside of base -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On Mon, Aug 06, 2007 at 01:36:54PM +0100, Neil Mitchell wrote:
Proposal:
Add System.Info.isWindows :: Bool
I was actually planning to propose something along similar lines this week, in order to replace ifdef's like in the GHC and library sources with pattern matches like I have done in Cabal, e.g.: -#if mingw32_HOST_OS || mingw32_TARGET_OS -dllExtension = "dll" -#else -dllExtension = "so" -#endif +dllExtension = case os of + Windows _ -> "dll" + _ -> "so" I haven't been through to look at what ifdef-replacements are needed, but I expect to want both OS = Linux | Windows Windows | ... | OtherOS String and Arch = I386 | AMD64 | Sparc | ... | OtherArch String types. Not all ifdefs will be able to be removed, e.g. because they use platform-specific packages or foreign imports. I don't know if it would be worth having other extensions to make elmiinating these ifdefs possible too. I would like it to be easy for an optimiser to dead-code-eliminate branches that don't apply (and in particular I would like it to be something that is DCEd by GHC so we don't carry around entire NCGs we can't use, for example). As long as that happens I don't really mind if it is done by pattern matching or by using isWindows-style functions. Doing equality tests against System.Info.os doesn't cut it, though. Finally, it needs to remain in base if we are to use it for ifdef-removal in the base libraries (and as low down in base as possible).
data OS = Linux | Windows Windows | ... etc | Other String data Windows = MingW
Since when did GNU build Windows operating systems?
It seemed to me that at some point we would be likely to want to distinguish between MingW | Cygwin | Native, but a lot of the time we'd want to just match Windows _.
You can add System.Info.libraries :: [Libary], and make MingW a library, but if you have a Windows enumeration it really should be for a list of Windows operating systems.
We'd need to do IO to do that, so it wouldn't fit my needs. Also, MingW `elem` libraries wouldn't get optimised out at compile time. It would be great if we could get all this into 6.8, as then we will be able to rely on it a year or so earlier.
There are lots of things that could go in System.Info, and I agree more should be moved along.
Ditto for these. Thanks Ian

Ian Lynagh wrote:
Finally, it needs to remain in base if we are to use it for ifdef-removal in the base libraries (and as low down in base as possible).
Would it be helpful to know the full set of platform-tests base currently uses, so we know a minimum of what tests we need in base? And... there is always the "code duplication" approach, if anything needs to be used in base as well as being upgradable, although I would not recommend that approach (unless with a detailed consideration) :-) Isaac

On Tue, Aug 07, 2007 at 01:04:59PM +0100, Ian Lynagh wrote:
On Mon, Aug 06, 2007 at 01:36:54PM +0100, Neil Mitchell wrote: I was actually planning to propose something along similar lines this week, in order to replace ifdef's like in the GHC and library sources with pattern matches like I have done in Cabal, e.g.:
-#if mingw32_HOST_OS || mingw32_TARGET_OS -dllExtension = "dll" -#else -dllExtension = "so" -#endif
+dllExtension = case os of + Windows _ -> "dll" + _ -> "so"
Yes, removing ifdefs like this is very important to compilers such as jhc that produce portable C code, it is very unlikely the answers to these questions are available at compile time. especially when bundling a library for distribution. I would also like to see nativeWordSize and nativePointerSize fields of type Int. sizeof (undefined :: CInt) and sizeof (undefined :: Ptr a) sort of work... but are rather convoluted for such a common thing that needs to be queried. for targeted compilers such as ghc, these will be compile time constants so will optimize away, for ones such as jhc, the actual determination of the values may be defered. John -- John Meacham - ⑆repetae.net⑆john⑈

On 6 aug 2007, at 12.26, Neil Mitchell wrote:
.... = os == "mingw"
This is wrong on so many levels!
I agree, but
Proposal:
Add System.Info.isWindows :: Bool
is hardly better, because this opens the door to political issues (why not have isLinux, isFreeBSD, isNetBSD, ...?) And I'm not even sure returning True for every Windows incarnation is the right thing in most use cases. In general you want to test for APIs--not the OS per se. I am much for an ADT instead of an unstandardized String, but having a battery of is<OS> is not a solution -- a library/program should be able to decide for itself how much info about it's environment it needs. (e.g., isWindows on cygwin depends really on what information you need, like for calling certain libraries, or just have a different UI style, etc.) / Thomas

Thomas Schilling wrote:
On 6 aug 2007, at 12.26, Neil Mitchell wrote:
.... = os == "mingw"
This is wrong on so many levels!
I agree, but
Proposal:
Add System.Info.isWindows :: Bool
is hardly better, because this opens the door to political issues (why not have isLinux, isFreeBSD, isNetBSD, ...?) And I'm not even sure returning True for every Windows incarnation is the right thing in most use cases. In general you want to test for APIs--not the OS per se.
Like it or not, Windows is a very significant, special case, where programs often transform themselves, more than they need to, based on a simple judgment of whether they're on "windows" or not, even when POSIX APIs are available, etc., etc. ***I don't like it either.*** But defining APIs is hard work, Windows is in practice much different from almost anything else, much more important, and many of us aren't interested in expending too much hard work to support (flexibly, in detail,) stupid closed-source platforms. Developers tend to want to check for isWindows anyway: they already do, with os=="mingw" and other hacks. ***I think isWindows is necessary, at least as a intermediate solution***... if someone makes more, API-specific queries sometime, then it will be easier to search existing code for the unified "isWindows" and find everywhere that might be improved. I vote *against* the name isMicrosoftWindows because the query *should* return True in ReactOS / Wine, assuming Haskell and them can be made to work at all! Any differences there, should be resolved by more detailed queries (e.g. Window OS version number! - or whatever they use for labelling their versions) Isaac

On Mon, Aug 06, 2007 at 06:04:41PM -0300, Isaac Dupree wrote:
Thomas Schilling wrote:
On 6 aug 2007, at 12.26, Neil Mitchell wrote:
.... = os == "mingw"
This is wrong on so many levels!
I agree, but
Proposal:
Add System.Info.isWindows :: Bool
is hardly better, because this opens the door to political issues (why not have isLinux, isFreeBSD, isNetBSD, ...?) And I'm not even sure returning True for every Windows incarnation is the right thing in most use cases. In general you want to test for APIs--not the OS per se.
Like it or not, Windows is a very significant, special case, where programs often transform themselves, more than they need to, based on a simple judgment of whether they're on "windows" or not, even when POSIX APIs are available, etc., etc. ***I don't like it either.*** But defining APIs is hard work, Windows is in practice much different from almost anything else, much more important, and many of us aren't interested in expending too much hard work to support (flexibly, in detail,) stupid closed-source platforms. Developers tend to want to check for isWindows anyway: they already do, with os=="mingw" and other hacks. ***I think isWindows is necessary, at least as a intermediate solution***... if someone makes more, API-specific queries sometime, then it will be easier to search existing code for the unified "isWindows" and find everywhere that might be improved.
Yes. I agree, I wouldn't want to see an enumerated data type, because you really want to query features the environment supports, not necessarily what OS. (like, ReactOS provides the win32 api) so, I'd actually like to see two isWindows :: Bool isPosix :: Bool where they say whether the given APIs are available (to some reasonable approximation). for instance, windows under mingw would be True,False, while windows under cygwin would be True,True and linux would be False,True. This covers the 'special' cases that most people have to worry about. I have nothing against a more complete API, but these two special cases are common and important enough that I think they should have special support. John -- John Meacham - ⑆repetae.net⑆john⑈

Hello Thomas, Tuesday, August 7, 2007, 12:24:00 AM, you wrote:
.... = os == "mingw"
is hardly better, because this opens the door to political issues (why not have isLinux, isFreeBSD, isNetBSD, ...?)
i bet that above-mentioned System.Info.os should alow to test for these situations. it return unix-specific string so it should be good to distinguish any unix OSes and only recognizing windows is a problem -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

We have not reached consensus on this issue yet. Based on informal chats with interested people, here is another concrete proposal: Instead of adding isWindows, isBeOS, isNixOS etc we have a simple enumeration of the major OS flavour: data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String osFlavour :: OSFlavour So no "subsystem" as fields of the OS constructors. This keeps it simple and covers many use cases. Adding more specific feature tests would probably cover most of the other use cases where we need more information than we can divine from the OS kind. So if people want isWindows or isUnixish predicates they can implement them easily in terms of this enumeration. This avoids us having to centrally agree an interpretation of what isUnixish might mean (so no arguments about whether ghc built to target cygwin is sufficiently unixish). If people feel it is really necessary, a separate build platform string could be added. This would be the system/platform/toolchain that the compiler targets: compilerBuild :: String eg for GHC on windows this would be "mingw32", "cygwin" or whatever. But I wonder if that's really necessary and if whatever people are testing on the basis of the build flavour couldn't be decided better with more specific feature tests. So I'd advocate a simple coarse OS classification and additional specific feature tests. Duncan

Hi By modifying your proposal ever so slightly (and probably as you intended anyway):
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String deriving Eq
(who wants to add an Ord instance? then we can really debate whether Windows > Linux or vice versa) Now we have (== Windows) which is only a few additional characters over isWindows, so is quite sufficient. Adding any further fields to the Windows constructor would destroy this nice property. Thanks Neil

On Wed, Aug 15, 2007 at 03:40:56PM +0100, Neil Mitchell wrote:
By modifying your proposal ever so slightly (and probably as you intended anyway):
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String deriving Eq
(who wants to add an Ord instance? then we can really debate whether Windows > Linux or vice versa)
We probably ought to have one, because sooner or later someone is bound to want to use OSFlavour as a map key or something. And Show, Read, Data and Typeable too. Thanks Ian

On Wed, 2007-08-15 at 16:49 +0100, Ian Lynagh wrote:
On Wed, Aug 15, 2007 at 03:40:56PM +0100, Neil Mitchell wrote:
By modifying your proposal ever so slightly (and probably as you intended anyway):
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String deriving Eq
(who wants to add an Ord instance? then we can really debate whether Windows > Linux or vice versa)
We probably ought to have one, because sooner or later someone is bound to want to use OSFlavour as a map key or something.
And Show, Read, Data and Typeable too.
Yes, Eq, Ord, Show and Read. I'm not sure it's possible to make it an instance of Data or Typeable is it? Doesn't that require a dependency on the generics package but System.Info is in the base package. Is everyone ok with the type name? OSFlavour, OSKind, OSType ? We can't use OSName since it's not that specific. Duncan

Hi
Yes, Eq, Ord, Show and Read.
I'm not sure it's possible to make it an instance of Data or Typeable is it? Doesn't that require a dependency on the generics package but System.Info is in the base package.
This is going to keep coming up, if we move the Data and Typeable classes out...
Is everyone ok with the type name? OSFlavour, OSKind, OSType ? We can't use OSName since it's not that specific.
OSFlavour - dislike, flavour pretty much means "it tastes like". Windows+Cygwin has flavours of both Windows and Unix. We want to say this is the OS you are using, its not just "a bit like" this one, but it really is, and it can only be one. OSType - seems fine. OSKind - again, has a slight "kind of like", and again Windows+Cygwin is kind of like multiple things. OSName - the name of your operating system - this is the one I would have picked. OS - nothing wrong with short names, especially when they are common abbreviations OperatingSystem - but no point optimising for character's when people are doing something we don't want them to be doing :-) I think in the end I'd pick OperatingSystem, as its very clear what it is. Thanks Neil

Is everyone ok with the type name? OSFlavour, OSKind, OSType ?
my immediate thought on seeing such run-together identifiers is that the designer didn't trust the hierarchical module system. ... or at least thought it too inconvenient. well, then - what exactly are the missing features here? Best regards, Johannes Waldmann.

On Wed, 2007-08-15 at 18:05 +0100, Neil Mitchell wrote:
Hi
Yes, Eq, Ord, Show and Read.
I'm not sure it's possible to make it an instance of Data or Typeable is it? Doesn't that require a dependency on the generics package but System.Info is in the base package.
This is going to keep coming up, if we move the Data and Typeable classes out...
That's what I keep saying. I must sound like a broken record.
Is everyone ok with the type name? OSFlavour, OSKind, OSType ? We can't use OSName since it's not that specific.
OSFlavour - dislike, flavour pretty much means "it tastes like". Windows+Cygwin has flavours of both Windows and Unix. We want to say this is the OS you are using, its not just "a bit like" this one, but it really is, and it can only be one.
OSType - seems fine.
OSKind - again, has a slight "kind of like", and again Windows+Cygwin is kind of like multiple things.
OSName - the name of your operating system - this is the one I would have picked.
Only it isn't the name, it's a general categorisation. The os name might be "Windows Vista(tm)" or "FreeBSD" but the os type is just Windows or BSD.
OS - nothing wrong with short names, especially when they are common abbreviations
OperatingSystem - but no point optimising for character's when people are doing something we don't want them to be doing :-)
I think in the end I'd pick OperatingSystem, as its very clear what it is.
I think I'd pick OSType as its very clear what it is. :-) The other thing is what the variable is called. We can't take System.Info.os since that already exists. If we pick OSType then it's easy, we pick System.Info.ostype. If it's OperatingSystem what would you pick? If we were starting from scratch I might advocate os :: OS and osName :: String, but we're not, we've already got os :: String. Duncan

From: libraries-bounces@haskell.org [mailto:libraries-bounces@haskell.org] On Behalf Of Duncan Coutts
Is everyone ok with the type name? OSFlavour, OSKind, OSType ? We can't use OSName since it's not that specific.
OSFlavour - dislike OSType - seems fine. OSKind - again, has a slight "kind of like" OSName - the name of your operating system
Only it isn't the name, it's a general categorisation. The os name might be "Windows Vista(tm)" or "FreeBSD" but the os type is just Windows or BSD.
OSFamily? Or OSGenre, OSGroup, OSCategory, OSClass, OSVariety, OSGenus, ... (Sorry, just ran on a bit with a thesaurus) Alistair ***************************************************************** Confidentiality Note: The information contained in this message, and any attachments, may contain confidential and/or privileged material. It is intended solely for the person(s) or entity to which it is addressed. Any review, retransmission, dissemination, or taking of any action in reliance upon this information by persons or entities other than the intended recipient(s) is prohibited. If you received this in error, please contact the sender and delete the material from any computer. *****************************************************************

On Wed, Aug 15, 2007 at 06:05:41PM +0100, Neil Mitchell wrote:
I'm not sure it's possible to make it an instance of Data or Typeable is it? Doesn't that require a dependency on the generics package but System.Info is in the base package.
This is going to keep coming up, if we move the Data and Typeable classes out...
They can move to below most other packages, and for those few that have to be lower down the instances can be put in the generics package. This won't be happening for 6.8, though. Thanks Ian

On Wed, Aug 15, 2007 at 05:57:38PM +0100, Duncan Coutts wrote:
On Wed, 2007-08-15 at 16:49 +0100, Ian Lynagh wrote:
On Wed, Aug 15, 2007 at 03:40:56PM +0100, Neil Mitchell wrote:
By modifying your proposal ever so slightly (and probably as you intended anyway):
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String deriving Eq
Is everyone ok with the type name?
No opinion on the type name, but the Other needs to be OtherOSFlavour (or Other<whatever name is chosen>) or it will clash with, e.g., the Other in Arch. Thanks Ian

Duncan Coutts wrote:
We have not reached consensus on this issue yet.
Based on informal chats with interested people, here is another concrete proposal:
Instead of adding isWindows, isBeOS, isNixOS etc we have a simple enumeration of the major OS flavour:
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String
test like (osFlavour == Windows) note some people may try to spell it as "osFlavor" MacOSX is completely different architecturally than the pre-X Mac OS (the latter of which, practically no one tries to support anymore, but at least _used to_ be worth mentioning in enumerations) Plain Solaris is rather different than Solaris spammed with GNU utilities etc... in the Unix world, OS's are not always so clear - but the core, kernel, stuff makes it clear as far as I'm aware of, and the rest is where particular feature tests are used. I suspect that people too often assume that the same features are available on all unixes, given how common it is to break on some of them. The common feature-set will likely be provided by haskell libraries anyway (in which case the libraries have to decide how to implement on each platform... okay) I don't like the way that enumeration scheme interacts with new OS's. What happens when/if Hurd or ReactOS or who-knows-what become viable OSes. Are they different enough from the other OSes that they should go in Other or (breakingly for any code that tries to detect it) be added to the enumeration? Seems to make an "isUnixLike" difficult to implement in terms of it... unless it's a feature test :) None of the existing OSes get subtypes... what if "Other" is also standalone, not having a String argument (and whenever someone wants to detect some other OS, I guess they petition to have the enumeration expanded and it will be promptly) - how is that on the problem scale?? It's a difficult question, taken generally. In some cases a haskell-program-user may even want to specify how to treat their environment (cygwin comes to mind). If only there was a decent package system- but I digress, Isaac

On 2007-08-15, Isaac Dupree
Duncan Coutts wrote:
We have not reached consensus on this issue yet.
Based on informal chats with interested people, here is another concrete proposal:
Instead of adding isWindows, isBeOS, isNixOS etc we have a simple enumeration of the major OS flavour:
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String
test like (osFlavour == Windows) note some people may try to spell it as "osFlavor"
Which is a point against the name.
MacOSX is completely different architecturally than the pre-X Mac OS (the latter of which, practically no one tries to support anymore, but at least _used to_ be worth mentioning in enumerations)
...
I don't like the way that enumeration scheme interacts with new OS's. What happens when/if Hurd or ReactOS or who-knows-what become viable OSes. Are they different enough from the other OSes that they should go in Other or (breakingly for any code that tries to detect it) be added to the enumeration? Seems to make an "isUnixLike" difficult to implement in terms of it... unless it's a feature test :)
Yes. This is guaranteed to be incomplete, and Other tells me nothing useful.
None of the existing OSes get subtypes... what if "Other" is also standalone, not having a String argument (and whenever someone wants to detect some other OS, I guess they petition to have the enumeration expanded and it will be promptly) - how is that on the problem scale??
It looks like a problem to me. If nothing else, as it expands, old packages get nasty warnings about incomplete pattern matches on old systems, and still don't work on new systems, as the package doesn't know how to handle this case. I don't care what exact operating system I'm running on, I care about features implemented, and APIs. This could be coded poorly on top of this, or coded directly. The enumeration adds /no/ value. isWin32 :: Bool, isPosix :: Bool, hasDTrace::Bool, hasXlib::Bool are useful. Adding a new feature test doesn't break old packages that don't use that feature.
Plain Solaris is rather different than Solaris spammed with GNU utilities etc... in the Unix world, OS's are not always so clear - but the core, kernel, stuff makes it clear as far as I'm aware of, and the rest is where particular feature tests are used.
What libraries are available is a big thing.
The common feature-set will likely be provided by haskell libraries anyway (in which case the libraries have to decide how to implement on each platform... okay)
When feasible, yes. But if a system lacks SysV IPC, it's not going to
It's a difficult question, taken generally. In some cases a haskell-program-user may even want to specify how to treat their environment (cygwin comes to mind).
Yeah. -- Aaron Denney -><-

Aaron Denney wrote:
None of the existing OSes get subtypes... what if "Other" is also standalone, not having a String argument (and whenever someone wants to detect some other OS, I guess they petition to have the enumeration expanded and it will be promptly) - how is that on the problem scale??
It looks like a problem to me. If nothing else, as it expands, old packages get nasty warnings about incomplete pattern matches on old systems, and still don't work on new systems, as the package doesn't know how to handle this case.
One should never have a case for "Other" anyway. Either case ... of Windows -> ... Linux -> ... _ -> ... --default behavior or case ... of Windows -> ... Linux -> ... --intentionally broken on unimplemented platforms --or _ -> error "not implemented on unknown platforms" should be used, anyway. That's good practice for anything like this, not just in Haskell, that is not inherently a fixed set: "isOther" is nonsensical to check for. (I am recalling that anti-"other" conclusion for file/directory/... information flags in C++ Boost.) Isaac

On 2007-08-15, Isaac Dupree
Aaron Denney wrote:
None of the existing OSes get subtypes... what if "Other" is also standalone, not having a String argument (and whenever someone wants to detect some other OS, I guess they petition to have the enumeration expanded and it will be promptly) - how is that on the problem scale??
It looks like a problem to me. If nothing else, as it expands, old packages get nasty warnings about incomplete pattern matches on old systems, and still don't work on new systems, as the package doesn't know how to handle this case.
One should never have a case for "Other" anyway. Either
Right. I meant adding OSes as they appear doesn't work well, not the case of Other having a string argument. -- Aaron Denney -><-

On Wed, 2007-08-15 at 22:02 +0000, Aaron Denney wrote:
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String
test like (osFlavour == Windows) note some people may try to spell it as "osFlavor"
Which is a point against the name.
Agreed.
I don't like the way that enumeration scheme interacts with new OS's. What happens when/if Hurd or ReactOS or who-knows-what become viable OSes. Are they different enough from the other OSes that they should go in Other or (breakingly for any code that tries to detect it) be added to the enumeration? Seems to make an "isUnixLike" difficult to implement in terms of it... unless it's a feature test :)
Yes. This is guaranteed to be incomplete, and Other tells me nothing useful.
Yes, as Issaac suggests perhaps we should drop the String parameter to OtherOS since it tells you nothing useful. Of course it's guaranteed to be incomplete but that doesn't make it useless. In reality it takes time to port a Haskell implementation to a completely new OS and the number of programs that might need to treat that platform specially is likely to grow only slowly, so there's enough time to get new enumeration values added.
None of the existing OSes get subtypes... what if "Other" is also standalone, not having a String argument (and whenever someone wants to detect some other OS, I guess they petition to have the enumeration expanded and it will be promptly) - how is that on the problem scale??
It looks like a problem to me. If nothing else, as it expands, old packages get nasty warnings about incomplete pattern matches on old systems, and still don't work on new systems, as the package doesn't know how to handle this case.
As Isaac says, you'd code these in a way where you pick out the exceptional cases and leave the rest for a default, so nothing should break if a new enum value is added.
I don't care what exact operating system I'm running on, I care about features implemented, and APIs.
This could be coded poorly on top of this, or coded directly. The enumeration adds /no/ value.
I think that's taking things to a bit of an extreme. Yes, feature tests are to be preferred where they can be clearly specified but there is some overhead to adding feature tests, there are many many situations where little distinctions are convenient.
isWin32 :: Bool, isPosix :: Bool, hasDTrace::Bool, hasXlib::Bool are useful.
Sure, but what about things which are really just proxies for the particular OS: usesWindowsStyleProgramInstallationLayout :: Bool
Adding a new feature test doesn't break old packages that don't use that feature.
Nor should adding enum values, tests should have a default. As Neil said in the first place, 90% of platform tests are actually: case osType of Windows -> _ -> So the model I'd advocate is to have a usable OS enumeration but look to identify what the common distinctions that people use it for and add specific feature tests for those common cases. We can accumulate more feature tests as they prove to be useful, but for the ones that slip through the gaps there's still a reasonably reliable fallback mechanism. We should collect suggestions for the some common ones, that might help this discussion. The obvious ones that have been suggested before include file extensions for certain file types like executables, shared libraries and object files. Duncan

On Thu, Aug 16, 2007 at 01:24:05AM +0100, Duncan Coutts wrote:
Yes, as Issaac suggests perhaps we should drop the String parameter to OtherOS since it tells you nothing useful.
You can match on OtherOS "BeOS" while you wait for the BeOS alternative to be added, although you do need a dash of CPP to support both old and new compilers once it has been added. Thanks Ian

On Thu, 2007-08-16 at 01:39 +0100, Ian Lynagh wrote:
On Thu, Aug 16, 2007 at 01:24:05AM +0100, Duncan Coutts wrote:
Yes, as Issaac suggests perhaps we should drop the String parameter to OtherOS since it tells you nothing useful.
You can match on
OtherOS "BeOS"
while you wait for the BeOS alternative to be added, although you do need a dash of CPP to support both old and new compilers once it has been added.
Hmm, but how is the base lib going to be set up to return OtherOS "BeOS"? This would have to be done during porting, wouldn't it be just as easy for said porter to add BeOS to the OSType enumeration? Duncan

On 8/15/07, Duncan Coutts
Hmm, but how is the base lib going to be set up to return OtherOS "BeOS"? This would have to be done during porting, wouldn't it be just as easy for said porter to add BeOS to the OSType enumeration?
I've agreed with Duncan so far. I'd like to note that its possible to add a string constant that contains the OS name/version/etc., completely separate from the enumeration. I vote for having the enumeration as Duncan's suggested, plus this separate string constant (maybe, OSString or OSVersion or something similar). Pete

On Thu, Aug 16, 2007 at 02:05:30AM +0100, Duncan Coutts wrote:
On Thu, 2007-08-16 at 01:39 +0100, Ian Lynagh wrote:
On Thu, Aug 16, 2007 at 01:24:05AM +0100, Duncan Coutts wrote:
Yes, as Issaac suggests perhaps we should drop the String parameter to OtherOS since it tells you nothing useful.
You can match on
OtherOS "BeOS"
while you wait for the BeOS alternative to be added, although you do need a dash of CPP to support both old and new compilers once it has been added.
Hmm, but how is the base lib going to be set up to return OtherOS "BeOS"? This would have to be done during porting, wouldn't it be just as easy for said porter to add BeOS to the OSType enumeration?
I was thinking of uname output, but it's true that GHC at least will just fail if it doesn't recognise the platform. I'm not sure about the other impls. Thanks Ian

On 2007-08-16, Ian Lynagh
On Thu, Aug 16, 2007 at 01:24:05AM +0100, Duncan Coutts wrote:
Yes, as Issaac suggests perhaps we should drop the String parameter to OtherOS since it tells you nothing useful.
You can match on
OtherOS "BeOS"
while you wait for the BeOS alternative to be added, although you do need a dash of CPP to support both old and new compilers once it has been added.
How does that work? How do you use CPP to check? -- Aaron Denney -><-

On 2007-08-16, Duncan Coutts
On Wed, 2007-08-15 at 22:02 +0000, Aaron Denney wrote:
It looks like a problem to me. If nothing else, as it expands, old packages get nasty warnings about incomplete pattern matches on old systems, and still don't work on new systems, as the package doesn't know how to handle this case.
As Isaac says, you'd code these in a way where you pick out the exceptional cases and leave the rest for a default, so nothing should break if a new enum value is added.
In many places there is no such thing as an exceptional case. This is tell us about things that aren't standardized. Not knowing how to do something tells us we can't do this, and need to abort. A feature test is exactly what we want.
I don't care what exact operating system I'm running on, I care about features implemented, and APIs.
This could be coded poorly on top of this, or coded directly. The enumeration adds /no/ value.
I think that's taking things to a bit of an extreme. Yes, feature tests are to be preferred where they can be clearly specified but there is some overhead to adding feature tests,
And also overhead to adding Enumeration types. Changing exposed datatypes breaks versioning.
there are many many situations where little distinctions are convenient.
Then they should be feature tests, of coures.
isWin32 :: Bool, isPosix :: Bool, hasDTrace::Bool, hasXlib::Bool are useful.
Sure, but what about things which are really just proxies for the particular OS:
usesWindowsStyleProgramInstallationLayout :: Bool
I think you mean: defaultPackageInstallationDirectory :: FilePath (which should be entirely overrideable, of course.)
Adding a new feature test doesn't break old packages that don't use that feature.
Nor should adding enum values, tests should have a default.
No, they shouldn't: defaults mean "oh, I haven't actually thought about this case. I'll assume it works like this." What happens when two OSes get added that treat something differently? An old package has no choice but to assume the same thing about both of them, and is guaranteed to be wrong about one, no matter how much foresight they have.
As Neil said in the first place, 90% of platform tests are actually:
case osType of Windows -> _ ->
Yes, but that's really case osType of Windows -> ... Unix -> ... If you're on something _truly_ different, such as VMS, or FooBazOS3.7 it /should fail/ instead of being treated as a Unix. Conversely, if it can work because it is just like a Unix in the features you need, it should work. We can get this by just looking at those features. If it has implementation for generic unix, and windows, then the proper test is if isWindows then ... else if isUnix then ... else error "No suitable implementation because..." Special per-OS hacks are simple, but wrong. A system that tells you what features work (such as GNU autoconfigure (or even perl's)) are the right thing, though can certainly be implemented better.
We should collect suggestions for the some common ones, that might help this discussion. The obvious ones that have been suggested before include file extensions for certain file types like executables, shared libraries and object files.
That's a reasonable start. One thing that has been brought up before is cygwin. Should it be considered a separate operating system? Well, not really, but it has much different conventions than standard windows. What we really want is not the underlying OS, but the "operating environment". What assumptions should the code make to work in the environment for which it is intended? This doesn't make much difference, except in terms of naming. -- Aaron Denney -><-

On Fri, 2007-08-17 at 00:55 +0000, Aaron Denney wrote:
On 2007-08-16, Duncan Coutts
wrote: On Wed, 2007-08-15 at 22:02 +0000, Aaron Denney wrote:
It looks like a problem to me. If nothing else, as it expands, old packages get nasty warnings about incomplete pattern matches on old systems, and still don't work on new systems, as the package doesn't know how to handle this case.
As Isaac says, you'd code these in a way where you pick out the exceptional cases and leave the rest for a default, so nothing should break if a new enum value is added.
In many places there is no such thing as an exceptional case. This is tell us about things that aren't standardized. Not knowing how to do something tells us we can't do this, and need to abort. A feature test is exactly what we want.
I don't care what exact operating system I'm running on, I care about features implemented, and APIs.
This could be coded poorly on top of this, or coded directly. The enumeration adds /no/ value.
I think that's taking things to a bit of an extreme. Yes, feature tests are to be preferred where they can be clearly specified but there is some overhead to adding feature tests,
And also overhead to adding Enumeration types. Changing exposed datatypes breaks versioning.
there are many many situations where little distinctions are convenient.
Then they should be feature tests, of coures.
And for little one-off feature tests, how should they be implemented in the absence of knowing the OS. Sure some can be specifically tested for, but some are not testable features exactly, they're just platform conventions...
usesWindowsStyleProgramInstallationLayout :: Bool
I think you mean: defaultPackageInstallationDirectory :: FilePath (which should be entirely overrideable, of course.)
But it's actually a good deal more complex that that, in that style it'd be: defaultPackageInstallationDirectory :: IO FilePath defaultBindir, defaultLibdir, ... :: IO FilePath in fact, I'm not sure it can be done in that style at all. Since on windows we're supposed to do relocatable installs and we're supposed to arrange to call the Win32 function to find the Program Files directory on the target machine and we have to generate source code to find the installation directory at runtime. This doesn't fit neatly into a generic test, any test would just be a proxy for isWindows. Really, the simplest method in this situation is just to have different code for Windows vs non-Windows. Some generic test(s) gains us nothing here. So given that such cases exist, lets allow people to do them slightly more reliably. Then in addition as we spot common patterns where generic feature tests would help we should try to standardise them.
Adding a new feature test doesn't break old packages that don't use that feature.
Nor should adding enum values, tests should have a default.
No, they shouldn't: defaults mean "oh, I haven't actually thought about this case. I'll assume it works like this." What happens when two OSes get added that treat something differently? An old package has no choice but to assume the same thing about both of them, and is guaranteed to be wrong about one, no matter how much foresight they have.
Having default cases or not doesn't make any difference, old programs can be broken on new OSs. So yes, that is certainly the advantage of feature tests but as I've pointed out not all cases fit neatly into nice generic feature tests.
Special per-OS hacks are simple, but wrong. A system that tells you what features work (such as GNU autoconfigure (or even perl's)) are the right thing, though can certainly be implemented better.
I am not arguing against feature tests! Where they work they're definitely nicer and more maintainable (though slightly more work to set up in the first place). However they do not cover all cases. Sometimes even it's necessary to implement a feature test as just a mapping from OS (eg directory separator char or text file line ending). This doesn't help as much with the maintainability at least it helps to collect OS specific info into one place in a program which makes porting easier. So I'm saying we need both. Duncan

Hi
A question for everyone: Excluding Cabal and GHC (which are where the
platform specific dependency stuff should be painfully explicit) has
anyone written a Haskell program which tests for a specific "feature"
of the host platform, i.e. os == "mingw32" or other?
For Win32 vs not Win32 I can list several: FilePath, lhs2tex, at least
5 or 6 I've flamed for the mingw32 bit...
Has anyone ever actually tested for anything else?
Thanks
Neil
On 8/17/07, Duncan Coutts
On Fri, 2007-08-17 at 00:55 +0000, Aaron Denney wrote:
On 2007-08-16, Duncan Coutts
wrote: On Wed, 2007-08-15 at 22:02 +0000, Aaron Denney wrote:
It looks like a problem to me. If nothing else, as it expands, old packages get nasty warnings about incomplete pattern matches on old systems, and still don't work on new systems, as the package doesn't know how to handle this case.
As Isaac says, you'd code these in a way where you pick out the exceptional cases and leave the rest for a default, so nothing should break if a new enum value is added.
In many places there is no such thing as an exceptional case. This is tell us about things that aren't standardized. Not knowing how to do something tells us we can't do this, and need to abort. A feature test is exactly what we want.
I don't care what exact operating system I'm running on, I care about features implemented, and APIs.
This could be coded poorly on top of this, or coded directly. The enumeration adds /no/ value.
I think that's taking things to a bit of an extreme. Yes, feature tests are to be preferred where they can be clearly specified but there is some overhead to adding feature tests,
And also overhead to adding Enumeration types. Changing exposed datatypes breaks versioning.
there are many many situations where little distinctions are convenient.
Then they should be feature tests, of coures.
And for little one-off feature tests, how should they be implemented in the absence of knowing the OS. Sure some can be specifically tested for, but some are not testable features exactly, they're just platform conventions...
usesWindowsStyleProgramInstallationLayout :: Bool
I think you mean: defaultPackageInstallationDirectory :: FilePath (which should be entirely overrideable, of course.)
But it's actually a good deal more complex that that, in that style it'd be:
defaultPackageInstallationDirectory :: IO FilePath defaultBindir, defaultLibdir, ... :: IO FilePath
in fact, I'm not sure it can be done in that style at all. Since on windows we're supposed to do relocatable installs and we're supposed to arrange to call the Win32 function to find the Program Files directory on the target machine and we have to generate source code to find the installation directory at runtime. This doesn't fit neatly into a generic test, any test would just be a proxy for isWindows.
Really, the simplest method in this situation is just to have different code for Windows vs non-Windows. Some generic test(s) gains us nothing here.
So given that such cases exist, lets allow people to do them slightly more reliably. Then in addition as we spot common patterns where generic feature tests would help we should try to standardise them.
Adding a new feature test doesn't break old packages that don't use that feature.
Nor should adding enum values, tests should have a default.
No, they shouldn't: defaults mean "oh, I haven't actually thought about this case. I'll assume it works like this." What happens when two OSes get added that treat something differently? An old package has no choice but to assume the same thing about both of them, and is guaranteed to be wrong about one, no matter how much foresight they have.
Having default cases or not doesn't make any difference, old programs can be broken on new OSs.
So yes, that is certainly the advantage of feature tests but as I've pointed out not all cases fit neatly into nice generic feature tests.
Special per-OS hacks are simple, but wrong. A system that tells you what features work (such as GNU autoconfigure (or even perl's)) are the right thing, though can certainly be implemented better.
I am not arguing against feature tests! Where they work they're definitely nicer and more maintainable (though slightly more work to set up in the first place). However they do not cover all cases. Sometimes even it's necessary to implement a feature test as just a mapping from OS (eg directory separator char or text file line ending). This doesn't help as much with the maintainability at least it helps to collect OS specific info into one place in a program which makes porting easier.
So I'm saying we need both.
Duncan
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Wed, 2007-08-15 at 17:38 -0300, Isaac Dupree wrote:
Duncan Coutts wrote:
We have not reached consensus on this issue yet.
Based on informal chats with interested people, here is another concrete proposal:
Instead of adding isWindows, isBeOS, isNixOS etc we have a simple enumeration of the major OS flavour:
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String
test like (osFlavour == Windows) note some people may try to spell it as "osFlavor"
Yes, good point. Another point for osType :: OSType in my opinion :-)
MacOSX is completely different architecturally than the pre-X Mac OS (the latter of which, practically no one tries to support anymore, but at least _used to_ be worth mentioning in enumerations)
Since nobody uses it, we don't need to distinguish it :-)
I don't like the way that enumeration scheme interacts with new OS's. What happens when/if Hurd or ReactOS or who-knows-what become viable OSes. Are they different enough from the other OSes that they should go in Other or (breakingly for any code that tries to detect it) be added to the enumeration? Seems to make an "isUnixLike" difficult to implement in terms of it... unless it's a feature test :)
The person who ports a Haskell implementation to an OS that isn't covered by the existing enumeration can add a new value to the enumeration and include that in their port and get it included in the current base package.
None of the existing OSes get subtypes... what if "Other" is also standalone, not having a String argument (and whenever someone wants to detect some other OS, I guess they petition to have the enumeration expanded and it will be promptly) - how is that on the problem scale??
Mm, that's an interesting point, perhaps the string isn't necessary. Duncan

On Wed, Aug 15, 2007 at 03:28:19PM +0100, Duncan Coutts wrote:
We have not reached consensus on this issue yet.
Based on informal chats with interested people, here is another concrete proposal:
Instead of adding isWindows, isBeOS, isNixOS etc we have a simple enumeration of the major OS flavour:
data OSFlavour = Linux | Windows | MacOS | BSD | Solaris | Other String
I really really dislike the 'Other String' thing, it is pretty much always a sign of bad design. Why would some OS's be delegated to 'Other' status just because we happened to not know about them at some point? will all code have to become bloated by saying case os of Linux -> doLinux Other s | s == "Linux" -> doLinux .... or have to use CPP to figure out if other hardcoded values of OSFlavor exist and must be checked for? the data type isn't "normalized" in some sense. there are multiple representations of the same thing, and it arbitrary elevates a few choices to special cases for no good reason. ones that make sense would be either
data OSFlavor = Linux | Windows | MacOS | BSD | Solaris
-- returns OSFlavor if we know it. getOsFlavor :: Maybe OSFlavor
or
newtype OSFlavor = OSFlavor String
However, I don't think either is really needed (but wouldn't hurt) because the practical question we want answered is not whether we are on Solaris or Linux usually, but rather we are on a machine that supports POSIX or if we are on a machine that supports the Win32 API. it is entirely possible to be both (cygwin under windows) for instance. We really should not hard code anything like this in data types. if we want a fast special purpose API (like what was originally proposed) then 'isWindows' is perfect. if we want a general way to query the system type, then a String (perhaps wrapped in a newtype) is the way to go. the halfway approach is the worst of both worlds and just complicates code so, avoid the 'Other'! it will make your code faster, smaller, and more clearly designed and understood. John -- John Meacham - ⑆repetae.net⑆john⑈

John Meacham wrote:
so, avoid the 'Other'! it will make your code faster, smaller, and more clearly designed and understood.
Thank you, I had a feeling there was something better than a word "Other" that you should never use! Now, can GHC use dead-code removal with something as complicated as a Maybe? Isaac
participants (11)
-
Aaron Denney
-
Bayley, Alistair
-
Bulat Ziganshin
-
Duncan Coutts
-
Ian Lynagh
-
Isaac Dupree
-
Johannes Waldmann
-
John Meacham
-
Neil Mitchell
-
Peter Gavin
-
Thomas Schilling