Skip to content

Conversation

@saul
Copy link
Contributor

@saul saul commented Nov 20, 2017

Fixes #3981, cc @0x53A

image

@saul
Copy link
Contributor Author

saul commented Nov 21, 2017

@cartermp this can be merged

@dhwed
Copy link
Contributor

dhwed commented Nov 21, 2017

While you're at it, can you also implement IReadOnlyDictionary<'Key,'T>?

@cartermp
Copy link
Contributor

cartermp commented Nov 22, 2017

@saul @0x53A does this work with the following program?

[<EntryPoint>]
let main argv = 
    let d = dict [("uh",1);("uhhh",2);("uhhhhhhhhhh",3)]
    let d2 = dict [("hello", 15); ("Wow", 10)]
    (d, d2) |> ignore // breakpoint here
    0 // return an integer exit code

Perhaps it's environmental, but when I install this PR into VS 15.5 Preview 4 I still see the old behavior.

@saul
Copy link
Contributor Author

saul commented Nov 22, 2017

Can’t test it at the moment - my screenshot is from manually linking the new FSharp.Core into my project.

@0x53A
Copy link
Contributor

0x53A commented Nov 22, 2017

@cartermp I've downloaded FSharp.Core.dll from https://ci2.dot.net/job/Microsoft_visualfsharp/job/master/job/release_net40_no_vs_windows_nt_prtest/4613/artifact/release/net40/bin/

And it looks really good:
grafik

Since this is part of FSharp.Core, not the VF#Tools, this would need a new nuget release.

@cartermp
Copy link
Contributor

I did a git clean -xdfsmorgasburg, rebuilt things, and it all works. 👍

@cartermp
Copy link
Contributor

@dhwed For IReadOnlyDictionary, I've created a tracking issue: #3999. I'd rather that be done separately from this PR, but if @saul is open to quickly doing it or accepting a PR into his branch from you, it won't be the end of the world if it comes in through this PR.

[<DebuggerBrowsable(DebuggerBrowsableState.RootHidden)>]
member x.Items = Array.ofSeq d

let dictImpl (comparer:IEqualityComparer<'SafeKey>) (makeSafeKey : 'Key->'SafeKey) (getKey : 'SafeKey->'Key) (l:seq<'Key*'T>) : IDictionary<'Key,'T> =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer inlined.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed

@saul saul changed the title Add debug visualiser for 'dict' Add debug visualiser for 'dict' and implement IReadOnlyDictionary/IReadOnlyCollection Nov 25, 2017
@saul
Copy link
Contributor Author

saul commented Nov 25, 2017

Implemented IReadOnlyDictionary and IReadOnlyCollection - I'll go around adding them to list, Map and Set (for a separate PR).

@cartermp
Copy link
Contributor

fsharp/fslang-design#234

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please

  • fix bug in TryGetValue mentioned above
  • add testing for all of IReadOnlyDictionary and IReadOnlyCollection,
  • review all existing testing for dict interfaces

thanks!

interface IReadOnlyDictionary<'Key, 'T> with
member __.Item with get key = t.[makeSafeKey key]
member __.Keys = t.Keys |> Seq.map getKey
member __.TryGetValue(key, value) = t.TryGetValue(makeSafeKey key, ref value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ref value is incorrect here - please use &value. Please also add a test for this and review all testing as there must be a test hole here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref seems to work fine for me? I've added tests to validate it - I'll use the & instead though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is my understanding that ref will not copy-out the resulting value to the byref passed as an argument

@saul
Copy link
Contributor Author

saul commented Nov 27, 2017

@dsyme there's a bit of a hiccup - dict currently returns IDictionary - this doesn't implement IReadOnly* interfaces. We can either create a new function called something like readOnlyDict that returns an IReadOnlyDictionary, or we can change dict to return some type in FSharp.Core that implements IDictionary and IReadOnly*, but I think that would break backwards compat.

How do you want to proceed?

@dsyme
Copy link
Contributor

dsyme commented Nov 27, 2017

@dsyme there's a bit of a hiccup - dict currently returns IDictionary - this doesn't implement IReadOnly* interfaces. We can either create a new function called something like readOnlyDict that returns an IReadOnlyDictionary, or we can change dict to return some type in FSharp.Core that implements IDictionary and IReadOnly*, but I think that would break backwards compat.

My assumption was that for now the return type should be only IDictionary and that would allow the change to be integrated straight away.

If you want to add readOnlyDict then please either add that to the RFC or make a new RFC and lets discuss there? I've no real issue with adding it but new API should always have multiple eyes and an RFC

@saul
Copy link
Contributor Author

saul commented Nov 28, 2017

Makes sense - will update the RFC tonight and use this PR as its implementation.

@KevinRansom
Copy link
Contributor

@dsyme, @saul saul ... is this ready? It looks like you agreed to a change, but I don't see the change.

Thanks

Kevin

@saul
Copy link
Contributor Author

saul commented Dec 17, 2017

@KevinRansom it's not quite ready yet - I started writing tests and fell down the rabbit hole of adding support for IEnumerable.Reset on seq {} enumerators. I'll see if I can make this change without that 😄

@saul
Copy link
Contributor Author

saul commented Dec 17, 2017

Pushed tests and new readOnlyDict top-level operator. Discussion to continue in fsharp/fslang-suggestions#624 and then the RFC will need updating, too.

@saul
Copy link
Contributor Author

saul commented Dec 18, 2017

Hmm not sure why the CI is failing... I've added that file to source control? cc @KevinRansom

@cloudRoutine
Copy link
Contributor

@saul what do you think of creating an additional project just for debugger visualizers? (not necessarily in this PR, but something to consider for the future)
The vsix packaging would install the dll of the visualizers to the right directory and vs should auto-load it
Although I'm not sure if these visualizers would show up in C# as well, but if we only write custom visualizers for F# types it'll probably be fine.

@saul
Copy link
Contributor Author

saul commented Dec 18, 2017

Visualizer in that sense is completely different to debug type proxies that are used in FSharp.Core.

@dsyme
Copy link
Contributor

dsyme commented Dec 19, 2017

Yes, I still believe this line is buggy: https://github.com/Microsoft/visualfsharp/pull/3988/files#diff-cf1d05f204f61f31020312fcec812dbaR84. That ref is reading the provided byref argument and creating a new ref cell, and never writing the result back to the byref argument.

@saul
Copy link
Contributor Author

saul commented Dec 19, 2017

Yeah @dsyme I’m happy to change it, but the TryGetValue tests pass (if you try it locally, the CI is failing)

Assert.AreEqual(irod.Values, [| 1; 4; 9|])

Assert.IsTrue(irod.TryGetValue(1, ref 1))
Assert.IsFalse(irod.TryGetValue(100, ref 1))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I read it, the test only verifies that the key is found, not that the correct value is returned. That may explain why it passes even though @dsyme is sure that the ref is incorrect.

A better test may be

let b,i = irod.TryGetValue(2)
Assert.AreEqual(true, b)
Assert.AreEqual(2, i)

@cartermp
Copy link
Contributor

cartermp commented Feb 5, 2018

(For posterity, since the jenkins servers to wipe results after a time)

11:42:56 Errors and Failures
11:42:56 
11:42:56 1) Failed : FSharp.Core.UnitTests.FSharp_Core.Microsoft_FSharp_Core.DictTests.IReadOnlyDictionary on readOnlyDict
11:42:56   Expected: 4
11:42:56   But was:  0
11:42:56 at FSharp.Core.UnitTests.FSharp_Core.Microsoft_FSharp_Core.DictTests.IReadOnlyDictionary on readOnlyDict() in D:\j\w\release_ci_pa---866fd2c3\tests\FSharp.Core.UnitTests\FSharp.Core\Microsoft.FSharp.Core\ExtraTopLevelOperatorsTests.fs:line 116
11:42:56 
11:42:56 2) Failed : FSharp.Core.UnitTests.SurfaceArea.SurfaceAreaTest.VerifyArea
11:42:56 Assembly: FSharp.Core, Version=4.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
11:42:56 Expected and actual surface area don't match. To see the delta, run:
11:42:56     windiff D:\j\w\release_ci_pa---866fd2c3\tests\FSharp.Core.UnitTests\SurfaceArea.net40.fs D:\j\w\release_ci_pa---866fd2c3\release\net40\bin\CoreUnit_net40_Xml.xml
11:42:56 
11:42:56 Unexpectedly missing (expected, not actual):
11:42:56 
11:42:56 Unexpectedly present (actual, not expected):
11:42:56     Microsoft.FSharp.Core.ExtraTopLevelOperators: System.Collections.Generic.IReadOnlyDictionary`2[TKey,TValue] CreateReadOnlyDictionary[TKey,TValue](System.Collections.Generic.IEnumerable`1[System.Tuple`2[TKey,TValue]])
11:42:56 at FSharp.Core.UnitTests.LibraryTestFx.SurfaceArea.verify(String expected, String platform, String fileName) in D:\j\w\release_ci_pa---866fd2c3\tests\FSharp.Core.UnitTests\LibraryTestFx.fs:line 142
11:42:56 
11:42:56 Run Settings
11:42:56     RuntimeFramework: V4.0
11:42:56     WorkDirectory: D:\j\w\release_ci_pa---866fd2c3\release\net40\bin
11:42:56     Verbose: True
11:42:56     NumberOfTestWorkers: 4
11:42:56 
11:42:56 Test Run Summary
11:42:56     Overall result: Failed
11:42:56    Tests run: 5344, Passed: 5342, Errors: 0, Failures: 2, Inconclusive: 0
11:42:56      Not run: 3, Invalid: 0, Ignored: 0, Explicit: 3, Skipped: 0
11:42:56   Start time: 2018-02-02 19:36:10Z
11:42:56     End time: 2018-02-02 19:41:41Z
11:42:56     Duration: 330.699 seconds
11:42:56 
11:42:56 Results (nunit3) saved as D:\j\w\release_ci_pa---866fd2c3\tests\TestResults\test-net40-coreunit-results.xml

@saul
Copy link
Contributor Author

saul commented Feb 5, 2018

At least it builds now :) the problem here is that seq computation expressions / Seq.map etc don’t support IEnumerable.Reset(). I just need to refactor the tests keeping this in mind

@saul
Copy link
Contributor Author

saul commented Feb 5, 2018

Scratch that, no it’s not. It’s the TryGetValue issue dsyme raised and the surface area change.

@saul
Copy link
Contributor Author

saul commented Feb 18, 2018

Okay, I think I've fixed the broken tests here. Sorry for the delay - my laptop makes it impossible to do dev work and I've just fixed my workstation after 3 months of it being broken 😄

@saul
Copy link
Contributor Author

saul commented Feb 18, 2018

@dotnet-bot test Ubuntu14.04 Release_default please

@cartermp
Copy link
Contributor

Sorry for the delay

No worries at all!

@cartermp
Copy link
Contributor

@dsyme can you re-review? Thanks!

@dsyme
Copy link
Contributor

dsyme commented Feb 21, 2018

LGTM

@cartermp
Copy link
Contributor

@dotnet-bot test Windows_NT Release_ci_part3 Build please

@KevinRansom
Copy link
Contributor

The issue is this:

an unexpected new public API:
Microsoft.FSharp.Core.ExtraTopLevelOperators: System.Collections.Generic.IReadOnlyDictionary2[TKey,TValue] CreateReadOnlyDictionary[TKey,TValue](System.Collections.Generic.IEnumerable1[System.Tuple`2[TKey,TValue]])

1) Failed : FSharp.Core.UnitTests.Portable.SurfaceArea.SurfaceAreaTest.VerifyArea
Assembly: FSharp.Core, Version=4.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Expected and actual surface area don't match. To see the delta, run:
    windiff D:\j\w\release_ci_pa---c6929ad7\tests\FSharp.Core.UnitTests\SurfaceArea.coreclr.fs \My Documents\CoreUnit_coreclr_Xml.xml

Unexpectedly missing (expected, not actual):

Unexpectedly present (actual, not expected):
    Microsoft.FSharp.Core.ExtraTopLevelOperators: System.Collections.Generic.IReadOnlyDictionary`2[TKey,TValue] CreateReadOnlyDictionary[TKey,TValue](System.Collections.Generic.IEnumerable`1[System.Tuple`2[TKey,TValue]])
at FSharp.Core.UnitTests.LibraryTestFx.SurfaceArea.verify(String expected, String platform, String fileName) in D:\j\w\release_ci_pa---c6929ad7\tests\FSharp.Core.UnitTests\LibraryTestFx.fs:line 171

Run Settings
    Internal Trace: Off

Test Run Summary
  Overall result: Failed
  Test Count: 5389, Passed: 5384, Failed: 1, Inconclusive: 0, Skipped: 4
    Failed Tests - Failures: 1, Errors: 0, Invalid: 0
    Skipped Tests - Ignored: 2, Explicit: 2, Other: 0
  Start time: 2018-03-14 17:52:10Z
    End time: 2018-03-14 17:56:18Z
    Duration: 248.537 seconds


@KevinRansom
Copy link
Contributor

@dotnet-bot test this please

@saul
Copy link
Contributor Author

saul commented Apr 8, 2018

@KevinRansom @cartermp this is ready to merge

@KevinRansom KevinRansom merged commit 2ccc1b3 into dotnet:master Apr 9, 2018
@KevinRansom
Copy link
Contributor

@saul

Thanks for this.

Kevin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants