Everything you can do to optimize Java, Ruby, Python, etc, you can also apply to C/C++, but the opposite isn't always true.
... at least assuming that "etc." includes high-level languages with real type systems that can actually prove properties of your code. Such languages can enable optimizations which are undecidable in C, C++, or any of the other mainstream languages.
However, there are more numbers in R than in Q, for example -- even though they're both infinite. See Cantor's diagonalization proof of the uncountability of R. Showing that Q is countably infinite is easy... you just have to realize that Q can be viewed as discrete points on a two-dimensional grid. Simply "connecting the dots" will provide a numbering scheme to map all those numbers to N (which is obviously countably infinite).
Except I have to convice my boss that Boost (sub-)libraries are (generally) solid. Normally you'd think that would be easy seeing as many Boost (sub-)libraries are getting into TR1 and are being regression tested on many platforms, and are written by some of the most brilliant C++ programmers on the planet. Unfortunaely my boss is a dumbass oldskooler who wouldn't recognize modern C++ if it raped his youngest daughter and who suffers from chronic NIH syndrome, meaning that all we get is shitty homegrown C++ libraries or glibc. With an all-batteries-included language we'd at least be spared the crappy home-grown reimplementations of the most basic stuff like regexes, shared_ptr, etc.
... such as "a square has four sides" and "2+2 = 4" all rest upon axioms which are (by definition) unprovable. That is to say: While proofs (as you say) are true and stay true independent of senses or feelings, the underlying assumptions (axioms) are not necessarily true. Conclusion: You cannot even trust mathematics if you do not trust the axioms.
Use LVM on top of MD/RAID. When enough of your physical drives have the requisite extra free space you can just create a *new* MD volume from the free space and add that to your logical volume. Example: If you had a 100GB drive with 1 partition in the RAID and replace it with a 150GB drive, say, you'd just allocate 100GB to 1 partition and allocate 50GB to a second partition, readding the first partition into the old RAID volume and waiting for it to rebuild. Do this for all your new drives. When enough of your drives have unused 50GB partitions you just create a new MD/RAID volume out of those and add that MD volume to your LV(s). Simple, really.
Unfortunately using refs can obscure the meaning of your code, specifically when used for "out" parameters -- ignoring the obvious const-ref usage. I've found that always using pointers for "out" parameters helps make it more obvious at the call site that something is being altered by a function/method call.
It's simply impossible to forget to delete with a shared_ptr... no matter how simple you make it to remember, you WILL forget to delete one of your pointers at some point (or several points). Any time you need to manually insert code to do something you're just increasing the number of things that can go wrong, better just to be safe and always use smart pointers.
Extra information = loads of profiling information which can only be collected at runtime. (Yeah, I know... you can also profile C programs and use profiles to generate better code. However, this does not take memory allocation patterns and such into account).
JIT compiles the Java bytecode to native machine code -- which is, at least theoretically, potentially faster code than a C or C++ compiler can generate because it has more information. Sure, you could say that you could just implement a JVM/JIT on top of C/C++ for every program you write and get the same performance, but that's just silly.
One thing which helps immensely is also having a strong type system with "sum" types, where you can declare types like
type state =
State1 with (all_data_pertaining_to_state1)
| State2 with (all_data_pertaining_to_state2)
| State3 with (all_data_pertaining_to_state3) ...
and just have one state variable of type state. This will:
ensure that you don't accidentally use state information that is not valid in a given state.
ensure that all the state transitions in your code explicitly state which information is carried from state to state
The other example is related to distribution and configuration managment. We have started using SSH communications central management center to distribute new versions [...]
Um, PIKT (and others like it) will do that for you, and that'll work for any program configurations you need to manage centrally -- at least when the configuration is based on text files of some sort. It will also allow you to manage configuration differences centrally and in a controlled and documented way instead of just having "one configuration copy for server A", "one configuration copy for server B", "one configuration copy for all the other servers".
Adding "central management" to each individual program is a bloody stupid idea since each will work differently, have different bugs, etc. etc.
doesn't scale well when you start doing class inheritence and having to worry about weakening of strengthening of constraints (you want to be able to weaken preconditions, but not post conditions or invariants) and so on
That's true of course... hadn't thought of that.
You can do DbC in Java, Python, and presumably other languages if you want, you're not just restricted to Eiffel. The catch is that those DbC systems require using add ons to the standard interpreters
In the case of Python you should be able to do it using a metaclass which automatically does the right thing and calls the appropriate __pre_$METHOD and __post_$METHOD (or whatever you'd like to call them) methods at the appropriate times. A bit messy, but not that messy.
why not just build it into the language? Is it really going to hurt anyone?
Porbably not, but good luck getting the C committe, or the Haskell people, or... to add it to their languages:). If you're designing a new language, sure, go for it... or you could try designing an extensible language and end up with LISP/Scheme.:)
Anyway, I'm done. I shouldn't really be wasting any more time on/.
what CSP is, actually, although details are a little fuzzy... I was introduced to it on one of those wet conferences. Apparently you just don't see the same connection between pure FP and CSP which I see... Let me see if I can explain more thoroughly:
My thinking is along the lines that e.g. the seq (is that the name? Like I said it's been a long time...) operator in CSP maps onto the "do" monad, likewise the par operator in CSP maps onto a parallel execution monad, etc. etc. The pure functional nature of Haskell means that there are no nasty side effects (aside from monads). So threading is basically trivial given enough knowledge about the properties of the compositional monads. The trouble is obtaining that enough knowledge about the monads to be able to parallelize effectively. In Haskell, monad behavior is (essentially) arbitrary, but in CSP you are restricted to a predefined set of compositional operators (monads). The fact that they have predefined concurrency semantics means that parallelism is "built into" the language and so the compiler can make assumptions that Haskell compilers cannot -- thus enabling more parallelism.
In the case of Eiffel I really think it's a case of not offering anything truly significant for programmer productivity. I mean, yeah, Design by Contract is generally a good idea, but it's nothing assert() and good coding standards can't provide. Non-trivial "contracts" can't be verified until run-time anyway, and assert() works just fine for that.
In the case of CSP... I must admit I'm not too familiar with it, but to me it seems rather like a restricted subset of purely functional programming. Of course, Occam is much lower level than, say, Haskell, but AFAICT all the CSP concepts have direct equivalents in Haskell, and the type system in Haskell is much richer. Given the choice I'd rather program (applications!) in Haskell.
(Anyway, I'm certainly no fan of C# or Java... their type systems are just too wimpy for my tastes...)
Your design is either OO or not OO, and the language that you implement it in is irrelevant.
By extension, you could just as easily say that the implementation language never matters, it's all just a Turing Machine(*) anyway. Except it does matter. Support for cleaner syntax, extra type checking, virtual/non-virtual method dispatch, etc. all matter when implementing an OO design. You can avoid whole classes of bugs by having proper language support, and programmer time can be reduced considerably.
(*) We'll conveniently ignore the fact that computers aren't really TMs here. The point is still valid.
... and those two words are: False Dichotomy.
However, there are more numbers in R than in Q, for example -- even though they're both infinite. See Cantor's diagonalization proof of the uncountability of R. Showing that Q is countably infinite is easy... you just have to realize that Q can be viewed as discrete points on a two-dimensional grid. Simply "connecting the dots" will provide a numbering scheme to map all those numbers to N (which is obviously countably infinite).
Make that /dev/urandom or you could end up waiting a loooooong time for it to finish.
Except I have to convice my boss that Boost (sub-)libraries are (generally) solid. Normally you'd think that would be easy seeing as many Boost (sub-)libraries are getting into TR1 and are being regression tested on many platforms, and are written by some of the most brilliant C++ programmers on the planet. Unfortunaely my boss is a dumbass oldskooler who wouldn't recognize modern C++ if it raped his youngest daughter and who suffers from chronic NIH syndrome, meaning that all we get is shitty homegrown C++ libraries or glibc. With an all-batteries-included language we'd at least be spared the crappy home-grown reimplementations of the most basic stuff like regexes, shared_ptr, etc.
... such as "a square has four sides" and "2+2 = 4" all rest upon axioms which are (by definition) unprovable. That is to say: While proofs (as you say) are true and stay true independent of senses or feelings, the underlying assumptions (axioms) are not necessarily true. Conclusion: You cannot even trust mathematics if you do not trust the axioms.
Network devices can AFAIK not be reached through /dev. (On Linux that is... I think it is true of the BSDs as well.)
(I'm assuming software RAID here, obviously.)
Use LVM on top of MD/RAID. When enough of your physical drives have the requisite extra free space you can just create a *new* MD volume from the free space and add that to your logical volume. Example: If you had a 100GB drive with 1 partition in the RAID and replace it with a 150GB drive, say, you'd just allocate 100GB to 1 partition and allocate 50GB to a second partition, readding the first partition into the old RAID volume and waiting for it to rebuild. Do this for all your new drives. When enough of your drives have unused 50GB partitions you just create a new MD/RAID volume out of those and add that MD volume to your LV(s). Simple, really.
Unfortunately using refs can obscure the meaning of your code, specifically when used for "out" parameters -- ignoring the obvious const-ref usage. I've found that always using pointers for "out" parameters helps make it more obvious at the call site that something is being altered by a function/method call.
It's simply impossible to forget to delete with a shared_ptr... no matter how simple you make it to remember, you WILL forget to delete one of your pointers at some point (or several points). Any time you need to manually insert code to do something you're just increasing the number of things that can go wrong, better just to be safe and always use smart pointers.
http://flashblock.mozdev.org/
shouldn't prevent network access.
Extra information = loads of profiling information which can only be collected at runtime. (Yeah, I know... you can also profile C programs and use profiles to generate better code. However, this does not take memory allocation patterns and such into account).
JIT compiles the Java bytecode to native machine code -- which is, at least theoretically, potentially faster code than a C or C++ compiler can generate because it has more information. Sure, you could say that you could just implement a JVM/JIT on top of C/C++ for every program you write and get the same performance, but that's just silly.
wookie from the planet Kashyyyk...
when I invent a device that allows me to stab people in the face over the Internet.
Um, PIKT (and others like it) will do that for you, and that'll work for any program configurations you need to manage centrally -- at least when the configuration is based on text files of some sort. It will also allow you to manage configuration differences centrally and in a controlled and documented way instead of just having "one configuration copy for server A", "one configuration copy for server B", "one configuration copy for all the other servers".
Adding "central management" to each individual program is a bloody stupid idea since each will work differently, have different bugs, etc. etc.
be relied upon for any information relating to the English language.
You underestimate the power of suggestion (and ignorance).
That's true of course... hadn't thought of that.
In the case of Python you should be able to do it using a metaclass which automatically does the right thing and calls the appropriate __pre_$METHOD and __post_$METHOD (or whatever you'd like to call them) methods at the appropriate times. A bit messy, but not that messy.
Porbably not, but good luck getting the C committe, or the Haskell people, or
Anyway, I'm done. I shouldn't really be wasting any more time on
what CSP is, actually, although details are a little fuzzy... I was introduced to it on one of those wet conferences. Apparently you just don't see the same connection between pure FP and CSP which I see... Let me see if I can explain more thoroughly:
My thinking is along the lines that e.g. the seq (is that the name? Like I said it's been a long time...) operator in CSP maps onto the "do" monad, likewise the par operator in CSP maps onto a parallel execution monad, etc. etc. The pure functional nature of Haskell means that there are no nasty side effects (aside from monads). So threading is basically trivial given enough knowledge about the properties of the compositional monads. The trouble is obtaining that enough knowledge about the monads to be able to parallelize effectively. In Haskell, monad behavior is (essentially) arbitrary, but in CSP you are restricted to a predefined set of compositional operators (monads). The fact that they have predefined concurrency semantics means that parallelism is "built into" the language and so the compiler can make assumptions that Haskell compilers cannot -- thus enabling more parallelism.
I hope that clears up what I was talking about.
In the case of Eiffel I really think it's a case of not offering anything truly significant for programmer productivity. I mean, yeah, Design by Contract is generally a good idea, but it's nothing assert() and good coding standards can't provide. Non-trivial "contracts" can't be verified until run-time anyway, and assert() works just fine for that.
In the case of CSP... I must admit I'm not too familiar with it, but to me it seems rather like a restricted subset of purely functional programming. Of course, Occam is much lower level than, say, Haskell, but AFAICT all the CSP concepts have direct equivalents in Haskell, and the type system in Haskell is much richer. Given the choice I'd rather program (applications!) in Haskell.
(Anyway, I'm certainly no fan of C# or Java... their type systems are just too wimpy for my tastes...)
We actually agree, it's just that I felt you being a bit over the top with that one statement. :)
By extension, you could just as easily say that the implementation language never matters, it's all just a Turing Machine(*) anyway. Except it does matter. Support for cleaner syntax, extra type checking, virtual/non-virtual method dispatch, etc. all matter when implementing an OO design. You can avoid whole classes of bugs by having proper language support, and programmer time can be reduced considerably.
(*) We'll conveniently ignore the fact that computers aren't really TMs here. The point is still valid.