Thread overview
Imports with versions
Oct 30, 2012
bearophile
Oct 30, 2012
Jacob Carlborg
Oct 30, 2012
Paulo Pinto
Oct 30, 2012
Jacob Carlborg
Oct 30, 2012
Paulo Pinto
Oct 30, 2012
H. S. Teoh
Oct 30, 2012
Jacob Carlborg
Oct 30, 2012
Jacob Carlborg
Oct 30, 2012
Paulo Pinto
Oct 31, 2012
Jacob Carlborg
October 30, 2012
There are some updated on the Java-like language Ceylon:

http://ceylon-lang.org/blog/2012/10/29/ceylon-m4-analytical-engine/


One of the features of Ceylon that seems interesting are the module imports:

http://ceylon-lang.org/documentation/1.0/reference/structure/module/#descriptor


An example:

doc "An example module."
module com.example.foo 1.2.0 {
    import com.example.bar 3.4.1
    import org.example.whizzbang 0.5;
}


I think it helps avoid version troubles.

A possible syntax for D:

import std.random(2.0);
import std.random(2.0+);

Bye,
bearophile
October 30, 2012
On 2012-10-30 01:51, bearophile wrote:
> There are some updated on the Java-like language Ceylon:
>
> http://ceylon-lang.org/blog/2012/10/29/ceylon-m4-analytical-engine/
>
>
> One of the features of Ceylon that seems interesting are the module
> imports:
>
> http://ceylon-lang.org/documentation/1.0/reference/structure/module/#descriptor
>
>
>
> An example:
>
> doc "An example module."
> module com.example.foo 1.2.0 {
>      import com.example.bar 3.4.1
>      import org.example.whizzbang 0.5;
> }
>
>
> I think it helps avoid version troubles.
>
> A possible syntax for D:
>
> import std.random(2.0);
> import std.random(2.0+);

It probably wouldn't be a bad idea to have this but wouldn't it be better to have a package manger to handle this.

-- 
/Jacob Carlborg
October 30, 2012
On Tuesday, 30 October 2012 at 08:44:48 UTC, Jacob Carlborg wrote:
> On 2012-10-30 01:51, bearophile wrote:
>> There are some updated on the Java-like language Ceylon:
>>
>> http://ceylon-lang.org/blog/2012/10/29/ceylon-m4-analytical-engine/
>>
>>
>> One of the features of Ceylon that seems interesting are the module
>> imports:
>>
>> http://ceylon-lang.org/documentation/1.0/reference/structure/module/#descriptor
>>
>>
>>
>> An example:
>>
>> doc "An example module."
>> module com.example.foo 1.2.0 {
>>     import com.example.bar 3.4.1
>>     import org.example.whizzbang 0.5;
>> }
>>
>>
>> I think it helps avoid version troubles.
>>
>> A possible syntax for D:
>>
>> import std.random(2.0);
>> import std.random(2.0+);
>
> It probably wouldn't be a bad idea to have this but wouldn't it be better to have a package manger to handle this.

.NET and OSGi are similar approaches, because they rely on dynamic linking.

The package manager only works with static linking, otherwise you might get into the situation it compiles fine, but runs into version conflicts when running. Common scenario to anyone doing Java development.

One issue both systems have problems solving is what to do when third party libraries have conflicting version requirements.

--
Paulo
October 30, 2012
On 2012-10-30 13:25, Paulo Pinto wrote:

> .NET and OSGi are similar approaches, because they rely on dynamic linking.
>
> The package manager only works with static linking, otherwise you might
> get into the situation it compiles fine, but runs into version conflicts
> when running. Common scenario to anyone doing Java development.

I would say, in this case, that you haven't specified the versions correctly.

> One issue both systems have problems solving is what to do when third
> party libraries have conflicting version requirements.

Yeah, this can be a problem.

-- 
/Jacob Carlborg
October 30, 2012
On Tuesday, 30 October 2012 at 15:00:03 UTC, Jacob Carlborg wrote:
> On 2012-10-30 13:25, Paulo Pinto wrote:
>
>> .NET and OSGi are similar approaches, because they rely on dynamic linking.
>>
>> The package manager only works with static linking, otherwise you might
>> get into the situation it compiles fine, but runs into version conflicts
>> when running. Common scenario to anyone doing Java development.
>
> I would say, in this case, that you haven't specified the versions correctly.

Not really.

Let's say you compile everything fine, but on the deployment
platform, some IT guy has the cool idea of changing some configuration
settings.

That change will have as side effect that some third party dependencies will now be matched to another version different than what was used by the package manager.

You'll spend a few hours trying to track down the issue, in case you forget about checking the dynamic resolution order.

This is why Plan 9, Singularity and the Go guys are so much against dynamic linking.

--
Paulo
October 30, 2012
On Tue, Oct 30, 2012 at 07:42:13PM +0100, Paulo Pinto wrote:
> On Tuesday, 30 October 2012 at 15:00:03 UTC, Jacob Carlborg wrote:
> >On 2012-10-30 13:25, Paulo Pinto wrote:
> >>.NET and OSGi are similar approaches, because they rely on dynamic linking.
> >>
> >>The package manager only works with static linking, otherwise you might get into the situation it compiles fine, but runs into version conflicts when running. Common scenario to anyone doing Java development.
> >
> >I would say, in this case, that you haven't specified the versions correctly.
> 
> Not really.
> 
> Let's say you compile everything fine, but on the deployment platform, some IT guy has the cool idea of changing some configuration settings.
> 
> That change will have as side effect that some third party dependencies will now be matched to another version different than what was used by the package manager.

But doesn't that mean the version wasn't correctly depended upon?

There should NEVER be generic dynamic library dependencies (i.e., "I can link with any version of libc"), because they are almost always wrong in some way. Maybe not obvious at first, but still wrong. They should always depend on the *exact* version (or versions) of a library. Anything else is fundamentally broken and will eventually cause headaches and sleepless nights.

Mind you, though, a lot of libraries have a totally broken versioning system. Many library authors believe that the version only needs to be bumped when the API changes. Or worse, only when the existing API changes (new parts of the API are discounted.) That is actually wrong. The version needs to be bumped every time the *ABI* changes. An ABI change can include such things as compiling with different flags, or with a different compiler (*cough*gdc*dmd*cough*), *even when the source code hasn't been touched*. Any library that breaks this rule is essentially impossible to work with, because there is no way to guarantee that what gets linked at runtime is actually what you think it is.

Unfortunately, in practice, both of the above are broken repeatedly.


T

-- 
We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare.  Now, thanks to the Internet, we know this is not true. -- Robert Wilensk
October 30, 2012
On 2012-10-30 19:42, Paulo Pinto wrote:

> Not really.
>
> Let's say you compile everything fine, but on the deployment
> platform, some IT guy has the cool idea of changing some configuration
> settings.
>
> That change will have as side effect that some third party dependencies
> will now be matched to another version different than what was used by
> the package manager.

Again, then you haven't specified the dependencies correctly. If you just specify that "foo" depends on "bar" then you have only yourself to blame. You need to specify the exact version, i.e. "bar-1.2.3". If you cannot specify the exact version of an indirect dependency then you're not using a very good tools.

RubyGems together with Bundler is a great package manager. You specify the direct dependencies of your software and the tool will write down all dependencies, direct and indirect, in a "locked" file, including all versions.

When you deploy your software it will install and use the packages from the "locked" file. Your code cannot access any other dependencies that is not listed in the file.

> You'll spend a few hours trying to track down the issue, in case you
> forget about checking the dynamic resolution order.
>
> This is why Plan 9, Singularity and the Go guys are so much against
> dynamic linking.

One can always do stupid things, it can be quite hard to protect yourself from that. I mean, the IT guy can just replace your newly deployed application with a different version and no static linking in the world can help you there.

-- 
/Jacob Carlborg
October 30, 2012
On 2012-10-30 21:02, H. S. Teoh wrote:

> But doesn't that mean the version wasn't correctly depended upon?
>
> There should NEVER be generic dynamic library dependencies (i.e., "I can
> link with any version of libc"), because they are almost always wrong in
> some way. Maybe not obvious at first, but still wrong. They should
> always depend on the *exact* version (or versions) of a library.
> Anything else is fundamentally broken and will eventually cause
> headaches and sleepless nights.
>
> Mind you, though, a lot of libraries have a totally broken versioning
> system. Many library authors believe that the version only needs to be
> bumped when the API changes. Or worse, only when the existing API
> changes (new parts of the API are discounted.) That is actually wrong.
> The version needs to be bumped every time the *ABI* changes. An ABI
> change can include such things as compiling with different flags, or
> with a different compiler (*cough*gdc*dmd*cough*), *even when the source
> code hasn't been touched*. Any library that breaks this rule is
> essentially impossible to work with, because there is no way to
> guarantee that what gets linked at runtime is actually what you think it
> is.
>
> Unfortunately, in practice, both of the above are broken repeatedly.

I completely agree. See my answer about RubyGems and Bundler:

http://forum.dlang.org/thread/ycigekrnsvjuulbxuxqr@forum.dlang.org#post-k6pc33:241ma3:241:40digitalmars.com

Packages in RubyGems are using Semantic Versioning:

http://semver.org/

Which is supposed to help with these problems. But Ruby doesn't have a problem with breaking an ABI.

-- 
/Jacob Carlborg
October 30, 2012
On Tuesday, 30 October 2012 at 20:08:04 UTC, Jacob Carlborg wrote:
> On 2012-10-30 19:42, Paulo Pinto wrote:
>
>> Not really.
>>
>> Let's say you compile everything fine, but on the deployment
>> platform, some IT guy has the cool idea of changing some configuration
>> settings.
>>
>> That change will have as side effect that some third party dependencies
>> will now be matched to another version different than what was used by
>> the package manager.
>
> Again, then you haven't specified the dependencies correctly. If you just specify that "foo" depends on "bar" then you have only yourself to blame. You need to specify the exact version, i.e. "bar-1.2.3". If you cannot specify the exact version of an indirect dependency then you're not using a very good tools.
>

This cannot be enforced on runtime for most languages, that was why I was generalizing.

For example C and C++ require the programmer to do this, somehow.

Java requires you bundled something like OSGi with your application.

From the languages I have real project experience, only Groovy and .NET provide out of the box mechanisms for runtime validations given in the package manager.

--
Paulo
October 31, 2012
On 2012-10-30 21:55, Paulo Pinto wrote:

> This cannot be enforced on runtime for most languages, that was why I
> was generalizing.
>
> For example C and C++ require the programmer to do this, somehow.

It's possible to change the path where a dynamic library is expected to be located after the application/library is compiled. The package manager can change this when installing a package.

> Java requires you bundled something like OSGi with your application.
>
> From the languages I have real project experience, only Groovy and .NET
> provide out of the box mechanisms for runtime validations given in the
> package manager.

It's one thing saying that your existing tools cannot handle this. It's an entirely different thing saying it's not possible.

-- 
/Jacob Carlborg