ayseff/morelinq

Provide MoreLinq as a Portable Class Library

Closed this issue · 21 comments

To widen the applicability of MoreLinq, it would be great if the library could 
also be provided as a Portable Class Library. I have done a first examination 
of what would be required in order to build a PCL out of MoreLinq, and my 
findings can be found in this answer to a StackOverflow question: 
http://stackoverflow.com/a/13700766/650012

Original issue reported on code.google.com by cureos...@gmail.com on 4 Dec 2012 at 10:28

I have created a clone in case anyone is interested in retrieving the Portable 
Class Library adaptation, at http://code.google.com/r/cureosab-morelinq/ . You 
can find the relevant commit here: 
http://code.google.com/r/cureosab-morelinq/source/detail?r=09bfaecbac3547bf8f079
5d3217d3229d0c03627

Original comment by cureos...@gmail.com on 4 Dec 2012 at 8:17

Any update on this issue?

The current state of the source code (rev. ac22aac7615b, July 9 2014) is ideal 
for a Portable Class Library. 

It is very easy to create a profile 344 PCL library in e.g. VS2013.2 which will 
target practically everything of interest: .NET 4 and higher, Windows 8 (Metro) 
and higher, Windows Phone Silverlight 8 and higher, Windows Phone 8.1, 
Silverlight 5, Xamarin.Android, Xamarin.iOS.

You only need to enter these compilation symbols in the .csproj file:
NO_SERIALIZATION_ATTRIBUTES;NO_EXCEPTION_SERIALIZATION;NO_TRACING
(3 files affected),

change the signature in the invocations of the ArgumentOutOfRangeException 
constructor in Repeat.cs and Subsets.cs (one of the PCL targets, Silverlight 5, 
does not support the "string, object, string" constructor, but it can be easily 
replaced with the "string, string" constructor),

and, finally, exclude "ToDataTable.cs" from the PCL project, since the 
System.Data namespace is only available in the .NET target.

It would be terrific if you could include a PCL project in the MoreLinq 
solution, and also publish a build of it on NuGet.

If you do not have the time or incentive to do this, would it be OK if I 
published such a PCL on NuGet instead?

Many thanks in advance!
Anders Gustafsson, Cureos AB

https://www.nuget.org/profiles/cureos

Original comment by cureos...@gmail.com on 4 Aug 2014 at 11:24

Two more things: 

1) I have now updated my MoreLINQ clone at 
https://code.google.com/r/cureosab-morelinq/ with the changes that I outline in 
the comment #2 above, so it would be super easy for you to merge these changes 
into the main line of MoreLINQ.

2) I referred to an incorrect PCL profile in comment #2 above; the relevant 
profile would be 328.

Original comment by cureos...@gmail.com on 4 Aug 2014 at 12:24

Original comment by azizatif on 5 Aug 2014 at 5:46

  • Changed state: Accepted
@cureos.ab Can you enable reviews on your clone?

Original comment by azizatif on 5 Aug 2014 at 5:49

Thanks for considering this request, @azizatif. I have now enabled reviews on 
the clone. While I am at it, I can also mention that I ran the unit tests 
(excluding ToDataTable and Trace tests) referencing the portable library, and 
all tests passed.

Original comment by cureos...@gmail.com on 5 Aug 2014 at 6:20

Original comment by azizatif on 5 Aug 2014 at 4:26

  • Changed state: Started
@cureos.ab:

> would it be OK if I published such a PCL on NuGet instead?

Submitting a nuspec for the portable version to your clone would certainly help 
speed things up.

Original comment by azizatif on 5 Aug 2014 at 4:34

  • Added labels: Milestone-Release1.0
Hi again Aziz,

I have now updated the portable project according to your requests. I have also 
added a unit test project for the portable library and a nuspec file based on 
the nuspec file for the original library. Please take a look at this to see if 
it fits.

Best regards,
Anders

Original comment by cureos...@gmail.com on 5 Aug 2014 at 9:06

+1 for adding the unit test project too. See my review:
https://code.google.com/r/cureosab-morelinq/source/detail?r=1c90b1c22fbbc4d2887e
187a33c390cc808a649d

Original comment by azizatif on 6 Aug 2014 at 5:50

@cureos.ab Based on review comments[1] and an attempt to fix the clone history, 
I'm attaching a Mercurial bundle with a v1 branch. You can start with a new 
clone and import the bundle by running:

hg pull -u bundle.hg

You should then switch to v1 branch, work on there and push to your clone and 
we can take it from there.
Let me know if anything is confusing.

[1] 
https://code.google.com/r/cureosab-morelinq/source/detail?r=3e0e2f80c24c4c2194bc
37404e6f5f733fc8fcdf

Original comment by azizatif on 8 Aug 2014 at 5:52

Attachments:

@azizatif Based on your bundle, I have now created a new clone with a cleaner 
commit history. You'll find it here: 
https://code.google.com/r/cureosab-morelinq-portable/source/list

I have added a tag "v1.0-portable" on which the PCL NuGet build could be based, 
and I have merged the "v1.0" changes into the "default" branch.

The project GUID:s are all different, i.e. MoreLinq and MoreLinq.Portable have 
different GUID:s etc. As I mentioned in a previous code comment, I think it 
makes sense to have it this way, since the .NET and PCL projects are 
functionally different. (And Visual Studio does not accept it either if I keep 
both projects in the same solution...) 

When it comes to assembly identity equivalence, I believe that the important 
things are that the strong names are equivalent, i.e. that the assemblies have 
the same name and are using the same .snk file.

Please have a look at my new clone to see if there are any further issues that 
you want me to deal with before the PCL NuGet package is ready for publishing.

Best regards,
Anders

Original comment by cureos...@gmail.com on 11 Aug 2014 at 9:02

@cureos.ab

>>
The project GUID:s are all different, i.e. MoreLinq and MoreLinq.Portable have 
different GUID:s etc. As I mentioned in a previous code comment, I think it 
makes sense to have it this way, since the .NET and PCL projects are 
functionally different. (And Visual Studio does not accept it either if I keep 
both projects in the same solution...) 
<<

You misunderstood me there. I meant that it seems odd for the MoreLinq.Portable 
project to change GUIDs between v1.x to 2.0 of the project. I wasn't expecting 
MoreLinq and MoreLinq.Portable to share the same GUID.

>>
When it comes to assembly identity equivalence, I believe that the important 
things are that the strong names are equivalent, i.e. that the assemblies have 
the same name and are using the same .snk file.
<<

You raise a point here that makes me think of another potential issue. What if 
a project uses two libs, one which is linked to MoreLinq and another to its 
portable version? Since they have the same identity, you'll probably get a 
conflict. I'm wondering therefore if it's a good idea at all to have the 
portable version share the same assembly name!

Original comment by azizatif on 11 Aug 2014 at 4:32

  • Added labels: Milestone-Release1.1, Priority-Medium
  • Removed labels: Milestone-Release1.0
Dear Aziz,

thank you for the clarification regarding the GUID:s. Now I understand what you 
mean. With the new clone, this issue has been fixed; v1 and v2 projects have 
the same GUID:s.

Regarding the naming: the goal should be that the portable and non-portable 
assemblies share as much code as possible, right? In that case, using both 
libraries in one application will inevitably lead to numerous method 
duplication conflicts. I think one would want to avoid as much as possible to 
use both libraries under these conditions. Given this, I don't think it is a 
problem that the libraries are named the same. Rather, the fact that they share 
the same strong name could be used as an advantage.

Best regards,
Anders

Original comment by cureos...@gmail.com on 11 Aug 2014 at 4:49

@cureos.ab I don't expect an app to consciously use the portable & non-portable 
version. If an app references 2 independent NuGet packages, each of which in 
turn uses MoreLINQ portable & non-portable, then the app developer won't have 
much chance to resolve the conflict without private builds. I'd just like to 
think this through before we conclude the issue.

Original comment by azizatif on 11 Aug 2014 at 6:57

Thanks, Aziz, I see your point. I am not sure, but for the scenario you are 
outlining, I actually think it is a benefit that the portable and non-portable 
packages have the same strong name. I believe (without having tested it) that 
if you in such an (.NET) application explicitly reference the non-portable 
assembly, the references to the PCL assembly will automatically be resolved. 

But I suppose we need to run a test to verify this :-) I can give it a try if 
you think it is worthwhile testing.

Best regards,
Anders

Original comment by cureos...@gmail.com on 11 Aug 2014 at 7:35

@cureos.ab If two packages copy a dependency on MoreLinq.dll (one using 
portable and the other not), you don't know which version will get 
used/deployed as one may override the other. If one of the lib uses a method 
not available in the portable version (e.g. Trace or ToDataTable) and the 
portable version is loaded then you will get a MissingMethodException at 
runtime.

Mixing identities between incompatible binaries sounds troublesome. Moreover, 
if we ever want the full version to depend on the portable one as a core in the 
future then one would have to split the identities anyhow. I think it might be 
safest to start out with distinct identities (as you had it first). Another 
option worth considering is to have one package but install the right binary 
depending on the target framework.

Original comment by azizatif on 11 Aug 2014 at 10:06

@azizatif I have now made a test as follows:

a) Create a Portable class library that references the PCL version of MoreLinq. 
This library contains a method "PortableMethod" which uses the MinBy method 
that is included in both the portable and non-portable versions of MoreLinq .
b) Create a .NET class library that references the non-portable version of 
MoreLinq. This library contains a method "NonPortableMethod" which uses the 
Trace method that is only included in the non-portable MoreLinq.
c) Create a .NET console application "ConsoleApp" that references the class 
libraries in a) and b), and calls both "PortableMethod" and "NonPortableMethod".

If I explicitly reference the *portable* MoreLinq assembly in "ConsoleApp", I 
*do* get a "MissingMethodException" when I run "ConsoleApp".

BUT! If I explicitly reference the non-portable MoreLinq assembly, or if do not 
reference either of the MoreLinq assemblies, "ConsoleApp" executes 
successfully, without throwing any exception.

It does seem that assembly resolution is capable of selecting the most specific 
assembly when there are multiple assemblies with the same strong name. And in 
any case, if the non-portable MoreLinq assembly is explicitly referenced, there 
should not be any doubt that the referenced assembly is used throughout the 
application.

However, if you still feel reluctant to use the same names for the portable and 
non-portable assemblies, I am fine with that too.

Otherwise, I am all in favor of incorporating the non-portable and portable 
libraries in one package. For NuGet MoreLinq users this would certainly be the 
most convenient approach. 

Do you want to make the final touches to the project and build files yourself? 
Otherwise, I can make any updates you find necessary to my clone and you can 
take it from there. Just let me know how you want me to proceed.

Best regards,
Anders

Original comment by cureos...@gmail.com on 12 Aug 2014 at 10:02

>>
It does seem that assembly resolution is capable of selecting the most specific 
assembly when there are multiple assemblies with the same strong name. 
<<

I don't think this is a feature of the assembly resolution. The console app may 
be incidentally working because the non-portable version in the bin overwrote 
the portable version.

Original comment by azizatif on 12 Aug 2014 at 10:28

@cureos.ab Thanks for your contribution, tests and patience with re-working the 
changes.

The following merge in your clone was breaking the build:
https://code.google.com/r/cureosab-morelinq-portable/source/detail?r=49f1311c8cc
d1bea9ae148edd041cd1406e8343d

In any event, I cherry-picked your relevant changesets (so your commits are 
attributed to you with the original timestamps) and have pushed them to the 
main repo.

I finally decided to go with distinct identities because it is the safest 
option for now that has the least chance for popping surprise.

The NuGet package is published, starting at version 1.1:
https://www.nuget.org/packages/MoreLinq.Portable/

Coinciding with that, I've also pushed morelinq version 1.1:
https://www.nuget.org/packages/morelinq/1.1.0/

Original comment by azizatif on 12 Aug 2014 at 10:35

  • Changed state: Fixed
Great, many thanks for your assistance and patience. Terrific to see that the 
PCL package is already published on NuGet.

Best regards,
Anders

Original comment by cureos...@gmail.com on 12 Aug 2014 at 10:43