Ayende @ Rahien

It's a girl

Challenge: C# Rewriting

Here is an interesting one. Can you write code that would take the first piece of text and would turn it into the second piece of text?

First (not compiling)

image

Second (compiling):

image

Hint, you can use NRefactory to do the C# parsing.

Comments

Roy Osherove
03/13/2009 02:59 PM by
Roy Osherove

sounds like something I'd use method_missing for...

but I'd need VB or C# for dynamic types first

Nathaniel Neitzke
03/13/2009 03:30 PM by
Nathaniel Neitzke

I also have been working on a document style database, mostly learning Erlang to understand CouchDB. I am curious about your choice of C# for the views though, it seems like you would want to use the DLR or boo for something like that. I can see where C# support would be nice but when you get to the point where you are doing this type of stuff in C# it is fitting a square peg in a round hole imho.

Andrew Davey
03/13/2009 03:43 PM by
Andrew Davey

How about you define the interface of the document type you are retreiving first. Then write the query with that.

It's like saying "I am going to get things that look like this ..."

followed by "this is how I do that".

Justin Chase
03/13/2009 03:45 PM by
Justin Chase

You could in C#4.0 if docs was a dynamic object. No need for NRefactory just implement method missing and pass in the xml document object.

josh
03/13/2009 03:45 PM by
josh

I agree with Nathaniel. Seems like a little quackfu goodness with Boo would make the syntax nicer. /just me

Frank Quednau
03/13/2009 04:09 PM by
Frank Quednau

Interestingly it's an expression. You could write against any ol' interface, parse the expression and create a new one that looks like the second.

Alternatively a regular expression should work well :)

Jan Limpens
03/13/2009 04:41 PM by
Jan Limpens

I actually prefer the second, compiling expression. It is more obvious what is happening and as doc.Title will not give me intellisense anyway, whats the motive of this syntax sugar?

When I first read this in the other post, I assumed that doc.Title was a regular property every doc has.

Ayende Rahien
03/13/2009 05:24 PM by
Ayende Rahien

Roy,

Not really. If you pound C# hard enough, you can generate dynamics.

Ayende Rahien
03/13/2009 05:26 PM by
Ayende Rahien

Nathaniel,

Take a look at the view syntax, vs. the couch db syntax.

I find that linq make this a LOT simpler. It is also resolving a lot of problems relating to how to create indexed views without schema.

Ayende Rahien
03/13/2009 05:27 PM by
Ayende Rahien

Andrew,

That is too much work.

The data is already there, having to specify it twice is violation of DRY

Ayende Rahien
03/13/2009 05:27 PM by
Ayende Rahien

Justin,

Yes, I know.

I am not willing to be tied to C# 4.0

Ayende Rahien
03/13/2009 05:28 PM by
Ayende Rahien

Josh,

Yes, it would.

But Boo doesn't have full Linq support yet, and in this case, Linq really IS the best syntax for this.

Ayende Rahien
03/13/2009 05:30 PM by
Ayende Rahien

Frank,

I am not sure how you would get this to compile against "any old interface", when you don't know what the interface is in the first place.

Ayende Rahien
03/13/2009 05:31 PM by
Ayende Rahien

Jan,

The second syntax is uglier, and it exposes implementation details that I would rather not have.

The idea is to get a nicer syntax for things.

configurator
03/13/2009 07:49 PM by
configurator

Ayende, I suggest rewriting the linq expressions, and not the C# code.

The pro is that no precompilation rewriting is necessary.

The con is that some interface has to be defined - but only so that the code will compile.

Tuna Toksoz
03/13/2009 07:54 PM by
Tuna Toksoz

Looks similar to what we used to do with NH Linq :)

yug
03/13/2009 09:07 PM by
yug

I agree with configurator, wouldn't touching the LINQ expressions be easier than introduction another layer of complexity?

Stefan Wenig
03/13/2009 11:31 PM by
Stefan Wenig

Confusing your whole tool chain - from R# to the debugger and back - with a small precompilation trick sounds bad enough. The verbose version is not that bad after all.

But dismissing the whole notion of defining interfaces (or schemas for that matter, where's the difference) as a violation of DRY?

Anyway, just defining the interfaces would not get you working code.. You might want to consider the XML features of VB (import <schema.xsd) - it's an excellent DSL for processing XML, and it might be extensible to map those XML properties to an indexer if you implement some funny interface.

Ayende Rahien
03/14/2009 01:00 AM by
Ayende Rahien

configurator,

I don't want to do that, I see this as a violation of DRY.

Ayende Rahien
03/14/2009 01:04 AM by
Ayende Rahien

Stefan,

I think that you are missing something, because I haven't explained it.

There isn't anything else here. Literally.

The code on this post is all the code that is required to create a view.

You are not going to be able to use standard tools anyway.

Stefan Wenig
03/14/2009 01:18 AM by
Stefan Wenig

As some people already pointed out, your first example will compile if you statically define an interface for doc. The advantage would be that you don't have to modify the tool chain (i.e., precompile C#).

I'm just saying that this will compile, but you still need to implement that interface (either statically or dynamically) in order for this code to work at run time.

(As for the rest of our answer: is this some kind of trick question where the real challenge is figuring out what the rules of the game are? I thought you're asking for that precompiler?)

configurator
03/14/2009 03:49 AM by
configurator

I don't see how defining a property is a violation of DRY. Is that property defined anywhere else? In the document itself, of course, but wouldn't the producer of the document (i.e. the same program) need the exact same interface anyway?

What good is a document that you can't access? And you can't access the document if you don't have an interface to access it with.

configurator
03/14/2009 03:51 AM by
configurator

If I understand you correctly, what you want is for all documents to always be dynamically bound (i.e. C# 4 type dynamic), never accessing them anyway else.

I can't shake the feeling that you are trying to coerce the language into something that it is not - a late-bound language. If you want a late-bound language, use VB or C# 4.

Ayende Rahien
03/14/2009 07:13 AM by
Ayende Rahien

Stefan,

No, this is not a trick question.

The problem is that when trying to change the parameters of the question, you are not aware of the context in which it is going to operate, so you are making the wrong assumptions.

There is going to be a pre compiler step anyway, so the objection about not having to change the tool chain is not valid. At that point, you might as well squeeze the most out of this operation, because good syntax matter.

Ayende Rahien
03/14/2009 07:21 AM by
Ayende Rahien

configurator,

You are confusing the db side code and the client side code. They are not in sync, not kept together and in general should be separated.

As such, when defining a view, having to define an interface for the view is redundant and violate DRY.

And yes, I am doing things that the language was never meant to do. That is part of the fun, because the end result is going to be worth it.

Stefan Wenig
03/14/2009 09:15 AM by
Stefan Wenig

I guess I'll have to wait for the answer to that challenge before I have a chance to understand your answers to my comments.

I was not trying to answer your question. Although it sounds interesting, I don't know the first thing about NRefactory and I'm lazy, so I'll just wait for the answer and then go look into NRefactory.

Neither was I changing the parameters of the question. I got off on a tangent about an alternative solution using interfaces with some other readers. And I made a general comment about whether the solution, as you defined it, would be worth a modification to the tool chain. I have thought about transformations in some cases where C# is unneccessarily limited (attribute argument types, for instance), and a simple precompiler step could bring huge benefits. Still, modifying the tool chain is a problem itself, and I finally decided not to do it.

But that''s not a relevant discussion if this is considered a challenge just for fun, so feel free to ignore my comments ;-)

Stefan Wenig
03/14/2009 12:49 PM by
Stefan Wenig

BTW, I just checked whether VB's XML support could help out here.

The syntax doc.Type == page would become doc.@Type = page in VB. That looks good enough (although only for string values, I didn't look any further).

However, VB's XML literals are unneccesarily bound to the XElement type (and some related types).

The resolution of .@Type is done via an extension method (AttributeValue) that VB will define for any assembly that uses those XML literals, but it will not use a user-provided method for other types. Also, the relevant methods in XElement are not virtual. (There might be a hack when you reach really deep into the data structures of XElement, but that's a place where I don't want to be.)

Unbelievable.

Ayende Rahien
03/14/2009 12:55 PM by
Ayende Rahien

Stefan,

I actually got to talk with the guy who implemented that feature not long ago.

That was an intentional decision on Microsoft part. They did not want to deal with supporting this extensibility story.

Stefan Wenig
03/14/2009 02:11 PM by
Stefan Wenig

Of course it is, that's just how they are wired. "Hey, this looks useful - can we make it internal?"

But making a framework's guts internal is one thing. While I don't agree with this default, at least they have given some good reasons. But binding a language's data access syntax to a non-virtual method of a concrete class is just ... unbelievable. I can't even access XML data without loading it into an XElement first.

There goes the idea of VB being my favorite DSL for XML ... at least the more interesting part of it.

Andrey Shchekin
03/15/2009 08:55 AM by
Andrey Shchekin

I would never want to do this. Did you like object-typed parameter in ASP.NET MVC? Dynamics (compile-time or runtime) are are problem waiting to happen.

Just use a generator to get a typed interface from the existing schema (you can easily do it through the pre-compile step), then compile this code referencing the generated interface.

If the DB has to be completely separated from this code, just extract some kind of schema from the DB (automatically), then generate an interface based on this schema.

Ayende Rahien
03/15/2009 09:00 AM by
Ayende Rahien

Andrey, there is no schema.

It is the view that defines the schema, and trying to define it twice is a waste of time.

Andrey Shchekin
03/15/2009 07:01 PM by
Andrey Shchekin

Ok, I read the CouchDB docs and it seems I understand the situation now.

Another question -- so you need a preprocessor since you do not only need to infer a schema, you also actually want to compile this (optionally using PLINQ or whatever)?

Otherwise you could just go with NRefactory without a compile step at all?

Ayende Rahien
03/15/2009 07:47 PM by
Ayende Rahien

Yes, I do want to compile this

Stefan Wenig
03/18/2009 09:31 AM by
Stefan Wenig

I read that wrong, I thought you were talking about extending C# with additional tooling, but this is about compiling code snippets from text fields, right?

Now everything makes sense, sorry for being so balky.

I still have reservations about not having a schema for the actual data though. The view makes up the schema, alright. But the view is created upon existing data, which should comply to one or more schemas (whether explicit or implicit), unless the view code is completely heuristic. That's a general problem that I have with schema-less data though. You avoid n schema migrations, but you have to deal with n versions of your data in the latest version of your code. But maybe that's just me being too enterprisey ;-)

Comments have been closed on this topic.