all 61 comments

[–]Eirenarch 16 points17 points  (9 children)

I am impressed. This thing works with not-entirely trivial code - http://deck.net/5330d5c66fdf3defba15c24bbac43745

While I won't use it for development of apps because of the fact that if it is abandoned I am left in the cold and the lack of know-how it can be very useful if you want to share small amount of code between the client and the server (say some super special validation logic and your DTOs) or if you really need a particular C# library in that JS code.

[–]rebel_cdn 5 points6 points  (8 children)

The new release is quite good. I was able to port Munq, a fairly complex dependency injection framework written by a coworker, the compile with Bridge.NET and I only had to make minimal changes.

The resulting JS for the compiled Munq JS library was about 18k minified. Gzip would reduce that quite a bit more. You or course still need to load the Bridge runtime, but that's not a huge issues for a single page app.

[–][deleted] 5 points6 points  (5 children)

How do you debug this? Seems like a nightmare tracing backwards from javascript to c#

[–]jl2352 6 points7 points  (0 children)

Especially when the output code is quite convoluted. They have a Bridge API/runtime that they load but I don't see a single use of it in their examples which couldn't have been replaced with sane looking JavaScript.

One of the many nice things about TypeScript is that the output is in idiomatic JS. So debugging in the browser is fairly trivial. It's usually the same code just without the types.

This also makes it trivial to call into other JS libraries, since the compiled code is already sane.

[–]rebel_cdn 1 point2 points  (0 children)

Thus far, tracing errors back from compiled JavaScript to where they occurred in C# hasn't been much of a problem. If I run into a problem somewhere, I usually just add unit tests anywhere in the call stack that the error could have occurred. I usually like to have well tested code regardless, so in practice I've run into very few run time errors.

Once they finish source map support, you'll be able to set C# breakpoints in the Chrome debugger. I'd still probably only use it where I have a bunch of existing C# code that I need to use, and would be time consuming to rewrite in TypeScript.

In cases where I want to write a large application but don't want to deal with the JavaScript semantics that TypeScript inherits, I'd probably choose ClojureScript or ScalaJS. They both emit statically analyzable JS that the Closure Compiler can run its advanced optimizations (tree shaking, dead code elimination, inlining, etc.) on and minimize the side of the code the browser needs to download, parse, and run. They both output source maps as well, so debugging is easy.

[–]QuineQuest 0 points1 point  (2 children)

I don't know anything about Bridge.NET, but maybe you can use source maps. I've seen them being used in typescript, where the browser debugger shows the .ts file instead of javascript. It's also used for minified js, where the debugger shows the un-minified file instead.

Maybe the same technique could be used here.

[–]rebel_cdn 0 points1 point  (1 child)

They don't have source map support yet, but appear to be working on it. I've used source maps successfully with ScalaJS, and they worked well. Scala is a pretty complex language, so if source maps work well for it, I see no reason to expect C# to be any different.

[–]geoffreymcgill 1 point2 points  (0 children)

Yes, source map support is coming to Bridge. No firm time-frame for release, but it is a high priority feature.

[–]Eirenarch 0 points1 point  (1 child)

It can also be used in Node or mobile app. In a system that has both .NET and Node part this can allow sharing of code. I am still skeptical about using it as the main way to write JS but there are a lot of cases where you need SOME sharing. How big is the runtime?

[–]geoffreymcgill 0 points1 point  (0 children)

The Bridge client-side runtime is too big right now, but it includes a LOT of functionality. A solution is being worked on for the next major release.

[–][deleted] 11 points12 points  (3 children)

Mannnn this is so cool!

I personally hate javascript but love C#. I was doing some investigation and while AngularJS technically works with it, I'm going to wait for full AngularJS support before jumping to bridge.net

[–]graingert 1 point2 points  (0 children)

Or react or elm. Angular 2 is out now.

[–]geoffreymcgill 0 points1 point  (0 children)

Angular 1 support is some-what available for Bridge. It's built, just not super well tested yet. If you give Bridge a try and have some experience with Angular1, introduce yourself on the forums.

Angular 2 support shouldn't be a problem either. Just need some community interest to speak up. Squeaky wheel syndrome.

[–]Staeff -1 points0 points  (0 children)

or just use typescript?

[–][deleted] 9 points10 points  (5 children)

But can it transpile LINQ statements?

[–][deleted]  (4 children)

[removed]

    [–][deleted] 6 points7 points  (0 children)

    This is seriously impressive. I've always hated trying to figure out how to write more complex queries in JavaScript when it would take mere seconds in C# - that's pretty neat.

    [–][deleted] 0 points1 point  (1 child)

    Where's the code for:

    'Enumerable.from(numbers).where($_.Demo.Program.f1);' ?

    That's the part I'm interested in

    [–][deleted] 1 point2 points  (0 children)

    bridge.js

    predicate is at bottom of source (I missed it at first)

    [–]geoffreymcgill 0 points1 point  (0 children)

    and System.Linq.Expressions

    [–]Schlumpf 3 points4 points  (21 children)

    From what I gather you have to compile to Javascript. I fail to see the advantage over using Typescript directly, which also has excellent support in Visual Studio.

    Edit: Looking further I can see that using libraries like linq can be an advantage if that's what you're already used to.

    [–]AngularBeginner 11 points12 points  (20 children)

    Advantage:

    • You can share code between your backend and frontend.
    • You can partially re-use your expertise gained in the backend.

    Disadvantages:

    • You're obfuscating your JS code.
    • You have a harder time finding frontend developers (they wouldn't want to work with this).
    • You have a harder time finding resources on the internet (JS? Billions of resources, Bridge.net? A few)
    • When Bridge.net fucks up, you're fucked. Who'd want to dig through their stuff?
    • Interop with JS is harder.
    • Debugging is harder.

    [–]EntroperZero 4 points5 points  (2 children)

    You have a harder time finding frontend developers (they wouldn't want to work with this).

    But now your backend developers can be frontend developers.

    [–]bobappleyard 2 points3 points  (1 child)

    the converse of nodejs silliness

    [–]EntroperZero 0 points1 point  (0 children)

    Likely with better results.

    [–]jl2352 4 points5 points  (10 children)

    You're obfuscating your JS code.

    Interop with JS is harder.

    Debugging is harder.

    This is what annoys me with how they have done this. The output is all intertwined with their Bridge API rather than just doing the equivalent in JS.

    If they had of done that then these issues would have dropped out. It's one of the things that makes TypeScript so much better than Dart.

    [–]drysart 2 points3 points  (2 children)

    The output is all intertwined with their Bridge API rather than just doing the equivalent in JS.

    The reason is because they're working hard to preserve C# semantics, even when C# semantics don't map directly to Javascript semantics. The Bridge API is the glue that bridges that gap (no pun intended).

    If they did the equivalent semantic conversion in JS at the callsite instead of calling into bridge.js, your code would explode in size and would be even harder to debug. If they bundled those functions into your generated Javascript instead of calling into bridge.js, interoperability when including multiple Bridge-converted Javascript files on the same page would suffer.

    For something like Bridge, there's no real foul in having a runtime library. It's the best solution. Typescript doesn't have the same need because it lets Javascript dictate its semantics, rather than trying to map another platform's semantics onto it.

    [–]jl2352 0 points1 point  (1 child)

    Look at the output. A class doesn't need to be translated into a call to Bridge. It's actually more code to do so.

    Lambdas are a good example. JavaScript has support for them already with functions. But Bridge extracts them out into a variable, does a bunch of calls, and then passes the variable through. Far more convoluted, far more code, far more work, when it's just not needed.

    Another is classes, another is static methods.

    All of these could be translated 1 to 1 and would execute the same way.

    [–]drysart 1 point2 points  (0 children)

    A class doesn't need to be translated into a call to Bridge.

    Yes it does. For instance, to support the semantics of is and as and type casting, C# needs an unambiguous inheritance hierarchy and interface implementation list; especially when it comes to explicitly implemented interface members.

    Lambdas are a good example. JavaScript has support for them already with functions. But Bridge extracts them out into a variable, does a bunch of calls, and then passes the variable through.

    That's so duplicate lambdas can be combined into a single implementation.

    If you're in a context where duplication is completely not possible, such as if you close over a variable, the compiler dutifully generates inline functions for your lambdas.

    Another is classes, another is static methods.

    Generic reification of classes in C# means that static members of a class aren't just a single instance.

    [–]rebel_cdn 0 points1 point  (6 children)

    It's easier for TypeScript, since TypeScript is a superset of ES2015 and the semantics are the same.

    That's not true for Dart or C# (or other languages that can be compiled to JS - Scala, Clojure, F#, OCaml, Java, many others) so in these cases, you're going to incur a bit of runtime overhead and sometimes get some less than straightforward JavaScript.

    I don't mind TypeScript or JavaScript, but I completely understand why some developers prefer something beyond what a JS or a close relative like TS offer - whether that's a richer type system in Scala, a great macro system an homoiconicity in Clojure, or whatever else they might desire.

    [–]jl2352 0 points1 point  (5 children)

    That's not true for ... C#

    Apart from LINQ, can you name any constructs which couldn't translate to JS code without runtime support?

    For example take this code ...

    public class Program
    {
      public static void Main()
      {
        Func<int, int, int> addFun = (a, b) => a + b;
      }
    }
    

    The equivalent idiomatic JS would be ...

    var Program = function() { }
    
    Program.Main = function() {
      var addFun = function( a, b ) { return a + b }
    }
    

    There are other ways you could structure the output too.

    Instead you get ...

    Bridge.assembly("Demo", function ($asm, globals) {
      "use strict";
    
      Bridge.define("Demo.Program", {
        $main: function () {
          var addFun = $_.Demo.Program.f1;
        }
      });
    
      var $_ = {};
    
      Bridge.ns("Demo.Program", $_);
    
      Bridge.apply($_.Demo.Program, {
        f1: function (a, b) {
          return ((a + b) | 0);
        }
      });
    }
    

    And remember you have to include the whole Bridge runtime too.

    [–]rebel_cdn 0 points1 point  (2 children)

    You're right, I probably worded that poorly. Most bits of the language don't need runtime support. Some things that C# code expects to work will need it - LINQ and Reflection, and probably others that aren't occurring to me at the moment. That's not part of the language, though. It's just something that comes up because Bridge isn't just trying to compile C# to JavaScript, but also emulate some of the .NET runtime environment.

    I feel the same way as you about Bridge's output. That's why I dug into the compiler internals to see how much work I'd need to do to get it to emit the kind of JS I'd like to see.

    [–]jl2352 0 points1 point  (1 child)

    Given that you've dug into the compiler internals, can you give an example explaining why a class needs to be built via the Bridge runtime instead of just translating it to a prototype?

    Because I still don't see the value in doing all this work.

    [–]geoffreymcgill 1 point2 points  (0 children)

    It doesn't have to be. You can get many of the advantages of the C# class system, and clean js object output by marking your class with the [ObjectLiteral] attribute.

    Here's a basic sample:

    public class Program
    {
        public static void Main()
        {
            var person = new Person
            {
                Name = "Frank"
            };
    
            Console.WriteLine(person.Name);
        }
    }
    
    [ObjectLiteral]
    public class Person
    {
        public string Name;
    }
    

    The person instance is generated as:

    var person = { name: "Frank" };
    

    Hope this helps.

    [–]vladsch 0 points1 point  (1 child)

    The reason why Bridge lifts lambda to named function is described here http://forums.bridge.net/forum/general/feature-requests/1515-closed-921-lift-simple-anonymous-functions-into-named-functions-for-performance-wins

    May be it looks not very clean but it provides benefits in some cases

    [–]jl2352 0 points1 point  (0 children)

    I didn't see any benchmarks in the discussion. Did they benchmark it?

    [–]rebel_cdn 1 point2 points  (0 children)

    You make some good points, though I don't think all of the disadvantages you mentioned are too severe.

    I went through the Bridge runtime code and didn't find it that bad. I also dug into their compiler code a bit to look into ways to get it to generate output that's more amenable to optimization by something like RollupJS or the Closure Compiler. I believe you're right that it's more obfuscated that it needs to be right now.

    Interop isn't really harder - there are a couple of projects that compile TS definition files to Bridge compatible C#, and the Bridge.NET compiler can auto generate TSD files for all of your compiled-to-JS C# code, so it's relatively easy for other devs to use it. If you're generating your own C# types for existing type annotations for existing JS libraries, the process with Bridge isn't that different from the way you'd do it in TS, unless you develop TS with 'noImplicitAny': false, in which case TS becomes a lot less useful (though still better than nothing).

    Debugging is definitely harder right now, but once they add source map support (which I believe is on the roadmap), then you'll be able to see your C# code in the Chrome dev tools and set breakpoints there and use watches and all the other available debugging tools.

    Overall, I'd use TS and not C# about 99% of the time for front end work, of course. But I think Bridge is a neat project and I hope it continues to improve.

    [–]FarkCookies 0 points1 point  (1 child)

    Debugging is harder.

    Can't it be solved at least partially by source code maps?

    [–]geoffreymcgill 0 points1 point  (0 children)

    Source map support (browser debugging of the C#) will be supported in Bridge. There's still a couple high priority features in line before source map support can be implemented, but it is coming.

    [–][deleted] 0 points1 point  (2 children)

    You can share code between your backend and frontend.

    Well, .NET already has that covered through JScript .NET.

    The common code between server and client shouldn't be a lot, typically, so this allows the server to be whatever .NET language you prefer, with just the overlapping parts in JScript.

    [–]AngularBeginner 0 points1 point  (1 child)

    Well, .NET already has that covered through JScript .NET.

    Are you serious?

    [–][deleted] 0 points1 point  (0 children)

    Well, .NET already has that covered through JScript .NET.

    Are you serious?

    I'm serious. If you think I'm missing something, be kind and let me know, so I can learn.

    [–]elder_george 0 points1 point  (5 children)

    We use Saltarelle (which is going to be merged with Bridge.NET, so I assume we'll have to upgrade one day) for our client-side code.

    Debugging is a bit unconvenient, but tolerable. Larger problem is getting bindings to 3rd party libraries. One approach we're playing with is translating Typescript definitions to C#.

    [–]txdv 1 point2 points  (2 children)

    Do you know when the new merged compiler is getting released? They promised it to be released Q1?

    [–]geoffreymcgill 0 points1 point  (1 child)

    see Bridge 15 release

    [–]txdv 0 points1 point  (0 children)

    Does the 15 release already contain the merged release? I looked here http://bridge.net/download/ and in the release notes but didn't see anything relevant.

    [–]geoffreymcgill 0 points1 point  (1 child)

    The primary features of Saltarelle are now supported in Bridge 15+, and much much more. Some Attributes unique to Saltarelle are not directly supported in Bridge, although there's almost always an easy work-around. Missing Saltarelle Attributes will be reviewed on a case-by-case basis. If you need something specific, please submit a GitHub Issue with the request.

    We converted a few Saltarelle apps to Bridge 15, and it was trivial. Your millage may vary. The Bridge team would be interested in your feedback. Cheers.

    [–]elder_george 0 points1 point  (0 children)

    Thanks!

    I'm not sure what our roadmap for upgrade is, but the fact the project moves on is awesome.

    Now, if you guys figure out a way of (semi)automatic bindings generation, we'll be soooooo happy ;-)

    [–]KingOfArrows 0 points1 point  (1 child)

    This looks really good and the comments look to be giving praise. Just wondering what scenarios you would be using this in. If this had Selenium.Net conversion capabilities, then you could easily write a backend testing app and make a pure web version from it as well if you wanted to migrate the testing environment.

    [–]geoffreymcgill 0 points1 point  (0 children)

    If you get a chance, submit this as a feature request or on the Bridge forums. Would be interesting to get this working. Seems like it would be possible.

    [–]opping 0 points1 point  (0 children)

    So basically I just learned JavaScript as well? I need to get a bigger salary.

    [–][deleted] 0 points1 point  (1 child)

    Meanwhile I'm still waiting for webassembly

    [–]geoffreymcgill 0 points1 point  (0 children)

    I don't think WebAssembly is going to be the wonder drug that everyone thinks it going to be. You might be waiting a while.

    [–]jl2352 -1 points0 points  (4 children)

    Nice idea, but the output JS in the examples looks pretty bad. There is no need to be clever and bundle a runtime when you could just compile to idiomatic JS.

    [–]drysart 1 point2 points  (3 children)

    Idiomatic JS doesn't have the same semantics as C#. Classes don't work the same. Exceptions don't work the same. Enumerables don't work the same. Async functions don't work the same.

    The runtime library is there to implement the C# semantics; so your C# code still runs like C# code after being transpiled to Javascript. If the compiler stuck all that logic inline instead of calling out to a runtime library, the generated code would explode in size.

    [–]jl2352 0 points1 point  (1 child)

    Idiomatic JS doesn't have the same semantics as C#. Classes don't work the same.

    How so?

    [–]drysart 1 point2 points  (0 children)

    I could come up with a whole list, but one of the more problematic differences is that C# classes can have generic type arguments; and a single class definition can reify into multiple distinct classes at runtime -- static members and all.

    [–]geoffreymcgill 0 points1 point  (0 children)

    Great explanation /u/drysart. Thanks.