Propose new feuture for csharp

  • Thread starter Thread starter sasha
  • Start date Start date
S

sasha

Hi!
Don't know if this forum read somebody from MS team. I suppose yes, so
propose new language future wich i need very much :-)

I think it would be nice to have in C# something like macros, but more
powerfull. Here is example:

// code frame
public codeframe MyCodeFrame
{
initialization
{
DataBase db = new DataBase();

try
{
db.StartTransaction();
}
finalization
{
db.Commit();
}
catch
{
db.Rollback();
throw;
}
}
}

// use this code frame inside some method:
....
usecodeframe(MyCodeFrame)
{
ob.RunCommand("INSERT INTO ...");
...
}
....

As a result of compillation i want to se instead of
usecodeframe(MyCodeFrame)
clause:

....
DataBase db = new DataBase();

try
{
db.StartTransaction();

ob.RunCommand("INSERT INTO ...");
...

db.Commit();
}
catch
{
db.Rollback();
throw;
}
....

I think this can be usefull for many people... Maby someone from MS
team can propose MS to implement this future in C# 4.0 :-)
 
Most people consider pure-textual macros to be a Bad Thing. MS has
included numerous code-generation libraries in the DotNet framework,
and ways to build codegen tools. Macros only really work cleanly in
homoiconic languages like Lisp - overreliance on text-based macros can
result in freakishly long compile-times (as seen in heavy use of C++
Templates) and poor design-time error validation.

MS has made their approach clear: if macro-like functionality is
needed, it should be done using code generation.

But if you really want macros, you can try Nemerle - it's DotNet
programming language designed to look similar to C# but with macros,
type-inference, and functional programming built-in.

Honestly, if MS was going to have a better metaprogramming system in
C#, they would've implemented it at the start and implemented much of
the language using it's model rather than hacking so many features in
later (Common Lisp does this - the whole OOP system in Lisp is a set of
macros).

My big "desired feature" for 3.0 is better linguistic support for
immutable objects - right now a general "copy object while changing
certain fields" is incredibly tedious to implement, and it is a very
common idiom for immutable structs.
 
Most people consider pure-textual macros to be a Bad Thing.

But i do not propose macros! I propose LANGUAGE construction!!!

I'm writing libruary for easy working with DB in transaction context...

So i have other querstion. I have class with Dispose method. I create
objects of this class inside of using, for example:

using(DBWrapper db = DBManager.CreateDBWrapper())
{
db.ExecuteNonQuery("INSERT INTO ..")

// for example here is devision by zere exception
int i = 100 / 0;

db.ExecuteNonQuery("INSERT INTO ..")
}

Now in DBWrapper.Dispose() i should know if i can COMMIT transaction or
must ROLLBACK it.

So i need know id Dispose method if exists unhendled exception or not.
How can i do this?

PS Please don't write about try/catch :-)
 
Why not just wrap that up in an object?

Because i need to place any not predefined code there...
 
sasha said:
Because i need to place any not predefined code there...

Then wrap that variable code in a delegate and pass the delegate as an
argument...?
 
sasha said:
But i do not propose macros! I propose LANGUAGE construction!!!

I'm writing libruary for easy working with DB in transaction context...

So i have other querstion. I have class with Dispose method. I create
objects of this class inside of using, for example:

using(DBWrapper db = DBManager.CreateDBWrapper())
{
db.ExecuteNonQuery("INSERT INTO ..")

// for example here is devision by zere exception
int i = 100 / 0;

db.ExecuteNonQuery("INSERT INTO ..")
}

Now in DBWrapper.Dispose() i should know if i can COMMIT transaction or
must ROLLBACK it.

So i need know id Dispose method if exists unhendled exception or not.
How can i do this?

PS Please don't write about try/catch :-)

I would write the code exactly as you did in your earlier post. Just
wrap the "variable code" in a delegate and pass the delegate as an
argument.

So... I wouldn't do the COMMIT / ROLLBACK in the Dispose method of your
DBWrapper class. IMHO that's an abuse of Dispose. Do something like
this instead:

public class void DoDatabaseTransation(DBCommandDelegate command)
{
using(DBWrapper db = DBManager.CreateDBWrapper())
{
try
{
command(db, ...);
db.Commit();
}
catch (...)
{
db.Rollback();
}
}
}

If your "command" needs variable arguments depending upon the
situation, as someone said just wrap it in an object:

public class void DoDatabaseTransation(DBCommand command)
{
using(DBWrapper db = DBManager.CreateDBWrapper())
{
try
{
command.Execute(db, ...);
db.Commit();
}
catch (...)
{
db.Rollback();
}
}
}

and

private class DBWhateverCommand : DBCommand
{
... constructor takes database command arguments ...
... override Execute method ...
}

then

DoDatabaseTransaction(new DBWhateverCommand(... arguments ...));
 
sasha said:
But i do not propose macros! I propose LANGUAGE construction!!!

I'm writing libruary for easy working with DB in transaction context...

So i have other querstion. I have class with Dispose method. I create
objects of this class inside of using, for example:

using(DBWrapper db = DBManager.CreateDBWrapper())
{
db.ExecuteNonQuery("INSERT INTO ..")

// for example here is devision by zere exception
int i = 100 / 0;

db.ExecuteNonQuery("INSERT INTO ..")
}

Now in DBWrapper.Dispose() i should know if i can COMMIT transaction or
must ROLLBACK it.

So i need know id Dispose method if exists unhendled exception or not.
How can i do this?

PS Please don't write about try/catch :-)

The problem is that commit and rollback could throw exceptions - and
throwing an exception in Dispose causes Very Bad Things to happen. So
your class can only be safely used in a Using(){} block.

Still, I'd just have an enum field OnDispose that you set to "Commit"
(default is Rollback) that you use before the end of the Using block.
That way you get the stack-style semantics you're looking for, but the
"Commit" only happens when the user really wants it to - telling the
object that it's safe to commit when disposed should be one of the last
things they do with it.

Either way, are you sure you're not re-inventing wheels? There are a
hojillion good ORM tools out there that take the user away from the
frustrations of ADO.NET - take a look at some of the features in LINQ
and systems like NHibernate.
 
Bruce said:
So... I wouldn't do the COMMIT / ROLLBACK in the Dispose method of your
DBWrapper class. IMHO that's an abuse of Dispose.

But what if other programmer forgot about direct Commit after
operations with DB?
Automatic commit/Rollback in Dispose will work always instead of direct
commit (as you propose and as it had been implemented in current
version of our library).

All propositions are possible to implement and most of them already had
been implemented. But all variants solve problem only partialy and cuse
quite a lot special code.
The main question of current topic is about how to write less code
to simplify writing of real usefull logic instead of spending time to
write down "technical" codes.
 
Martin said:
The problem is that commit and rollback could throw exceptions - and
throwing an exception in Dispose causes Very Bad Things to happen. So
your class can only be safely used in a Using(){} block.

What is the problem with commit/rollback in dispose? I just use
try/catch there.
Question about not using of try/catch/finally in code which use our
DBWrapper.

Still, I'd just have an enum field OnDispose that you set to "Commit"
(default is Rollback) that you use before the end of the Using block.
That way you get the stack-style semantics you're looking for, but the
"Commit" only happens when the user really wants it to - telling the
object that it's safe to commit when disposed should be one of the last
things they do with it.

This need direct specification of Commit after all operations. This can
be forgoted by not experienced user of library.
Either way, are you sure you're not re-inventing wheels? There are a
hojillion good ORM tools out there that take the user away from the
frustrations of ADO.NET - take a look at some of the features in LINQ
and systems like NHibernate.

Sure, partialy it is re-inventing wheel :) Like other 90% of codes:)
But we have some specific features in our project which prevent us from
using NHibernate. And our project is reimplementaion of our old
library. So for us it have more sence to improve our library instead of
using others...

Maybe again little more about idea of the topic.
Current topic is not about problems we have now and can't solve
ourselves. This is more about thing which is usefull in many cases not
only for our current situation.
 
Generally i propose universal solution.

But for our case i can propose other easy language extension.

The propose is next:
1) Create standart interface, something like this:

interface IUsungErrorHandler
{
public void OnInsideUsingError(Exception e);
}

2) To enhance compiler: when compiler find using block, it should check
if class inside using implements IUsungErrorHandler interface. If so,
than it should call MyClass.OnInsideUsingError method before Dispose
call.

In such case i'll can RollBack transaction in
MyClass.OnInsideUsingError method in case of error and Commit
transaction if no errors occured...
 
I withdraw my "commit" suggestion - Bruce's use of delegates is far
more elegant than my library-ish suggestion. Very Smalltalkish (or
Lispish, if you swing that way). Use a delegate to implement a custom
block, and provide an object that provides the functionality that is
only reasonable in the context of a transaction to that delegate...
then dispose of the functionality-object after calling the delegate
(through a using block), and commit if no exception occurred in the
DBCommandDelegate. This properly does all your requirements, and then
some. It controls access to transacted commands to only be useable
within the DBCommandDelegate, it commits on success of the
DBCommandDelegate, and rollsback if an exception is thrown.

I would still go a step further and require that the transaction
delegate return a bool (or enum) to indicate committment - this forces
the user to say "yes, I want to commit" but the compiler will prevent
them from ommitting it and allowing a rollback with a "not all
codepaths return a value" error. The return value could alternately be
a more complicated object if there is other "required" statements that
vary depending on conditional code within the DBCommandDelegate.

In other words, change it to:

public class void DoDatabaseTransation(DBCommandDelegate command)
{
using(DBWrapper db = DBManager.CreateDBWrapper())
{
try
{
bool res = command(db, ...);
if (res) db.Commit(); else db.Rollback();
}
catch (...)
{
db.Rollback();
}
}

}

Damn, I need to have more fun with these
anonymous-delegates-as-custom-blocks tricks.
 
Damn, I need to have more fun with these anonymous-delegates-as-custom-blocks tricks.

Thanks all for advices. I've made what i need using anonimous delegates
something like this:

new DBManipulator(MappingManager.Storer.DBFactory).Manipilate(
delegate(DBOperationBlock ob)
{
ob.ExecuteNonQuery(clause);
...
}
);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top