with
声明に関する私の回答に対するAlan Storm のコメントは、私に考えさせました。この特定の言語機能を使用する理由を見つけることはめったにありませんでしたし、それがどのように問題を引き起こす可能性があるかについてもあまり考えたことがありませんでした. with
さて、落とし穴を避けながら を効果的に利用するにはどうすればよいか、興味があります。
with
このステートメントはどこで役に立ちましたか?
with
声明に関する私の回答に対するAlan Storm のコメントは、私に考えさせました。この特定の言語機能を使用する理由を見つけることはめったにありませんでしたし、それがどのように問題を引き起こす可能性があるかについてもあまり考えたことがありませんでした. with
さて、落とし穴を避けながら を効果的に利用するにはどうすればよいか、興味があります。
with
このステートメントはどこで役に立ちましたか?
今日、別の使用法が発生したので、私は興奮してWebを検索し、その既存の言及を見つけました:ブロックスコープ内の変数の定義。
JavaScriptは、CおよびC ++に表面的に類似しているにもかかわらず、変数を次のように定義されているブロックにスコープしません。
var name = "Joe";
if ( true )
{
var name = "Jack";
}
// name now contains "Jack"
ループ内でクロージャを宣言することは、これがエラーにつながる可能性がある一般的なタスクです。
for (var i=0; i<3; ++i)
{
var num = i;
setTimeout(function() { alert(num); }, 10);
}
forループは新しいスコープを導入しないため、同じnum
(値が2
)が3つの関数すべてで共有されます。
let
およびwith
ES6let
にステートメントが導入されると、これらの問題を回避するために、必要に応じて新しいスコープを簡単に導入できるようになります。
// variables introduced in this statement
// are scoped to each iteration of the loop
for (let i=0; i<3; ++i)
{
setTimeout(function() { alert(i); }, 10);
}
あるいは:
for (var i=0; i<3; ++i)
{
// variables introduced in this statement
// are scoped to the block containing it.
let num = i;
setTimeout(function() { alert(num); }, 10);
}
ES6が広く利用可能になるまで、この使用は、トランスパイラーを使用することをいとわない最新のブラウザーと開発者に限定されたままです。ただし、次を使用してこの動作を簡単にシミュレートできますwith
。
for (var i=0; i<3; ++i)
{
// object members introduced in this statement
// are scoped to the block following it.
with ({num: i})
{
setTimeout(function() { alert(num); }, 10);
}
}
ループは意図したとおりに機能し、0〜2の値を持つ3つの個別の変数を作成します。C++でのブロックの動作とは異なり、ブロック内で宣言された変数はスコープされないことに注意してください(Cでは、変数はブロックなので、ある意味で似ています)。この動作は、実際には以前のバージョンのMozillaブラウザで導入されたlet
ブロック構文と非常に似ていますが、他の場所では広く採用されていません。
私はスコープ付きインポートの単純な形式として with ステートメントを使用してきました。ある種のマークアップビルダーがあるとしましょう。書くのではなく:
markupbuilder.div(
markupbuilder.p('Hi! I am a paragraph!',
markupbuilder.span('I am a span inside a paragraph')
)
)
代わりに次のように書くこともできます:
with(markupbuilder){
div(
p('Hi! I am a paragraph!',
span('I am a span inside a paragraph')
)
)
}
このユースケースでは、割り当てを行っていないため、それに関連するあいまいさの問題はありません。
with
私の以前のコメントが示したように、どのような状況でどんなに魅力的であっても、安全に使用できるとは思いません. この問題はここでは直接カバーされていないので、繰り返します。次のコードを検討してください
user = {};
someFunctionThatDoesStuffToUser(user);
someOtherFunction(user);
with(user){
name = 'Bob';
age = 20;
}
これらの関数呼び出しを注意深く調査しない限り、このコードの実行後にプログラムの状態がどうなるかを知る方法はありません。user.name
がすでに設定されている場合は、 になりますBob
。設定されていない場合、グローバルname
は初期化または変更されBob
、user
オブジェクトはname
プロパティなしで残ります。
バグが発生します。withを使用すると、最終的にこれが実行され、プログラムが失敗する可能性が高くなります。さらに悪いことに、with ブロックでグローバルを設定する作業コードに遭遇する可能性があります。これは、意図的に、または作成者が構造のこの癖を知らずに行うためです。これは、スイッチでフォール スルーが発生するのとよく似ています。作成者がこれを意図しているかどうかはわかりません。また、コードを「修正」すると回帰が発生するかどうかを知る方法はありません。
現代のプログラミング言語は機能がぎっしり詰まっています。一部の機能は、何年も使用した後、不適切であることが判明したため、使用を避ける必要があります。Javascriptwith
もその 1 つです。
with
最近、このステートメントが非常に役立つことがわかりました。この手法は、現在のプロジェクト (JavaScript で記述されたコマンド ライン コンソール) を開始するまで、まったく思い浮かびませんでした。特別なコマンドをコンソールに入力できる Firebug/WebKit コンソール API をエミュレートしようとしていましたが、それらはグローバル スコープの変数をオーバーライドしません。Shog9の優れた回答へのコメントで言及した問題を克服しようとしたときに、これを考えました。
この効果を実現するために、2 つの with ステートメントを使用して、グローバル スコープの背後にスコープを「階層化」しました。
with (consoleCommands) {
with (window) {
eval(expression);
}
}
この手法の素晴らしい点は、パフォーマンス上の欠点は別として、with
ステートメントの通常の懸念に悩まされないことです。なぜなら、とにかくグローバル スコープで評価しているためです。疑似スコープ外の変数が変更されました。
驚いたことに、他の場所で使用されているのと同じ手法を見つけることができたとき、この回答を投稿することに触発されました-Chromiumソースコード!
InjectedScript._evaluateOn = function(evalFunction, object, expression) {
InjectedScript._ensureCommandLineAPIInstalled();
// Surround the expression in with statements to inject our command line API so that
// the window object properties still take more precedent than our API functions.
expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }";
return evalFunction.call(object, expression);
}
編集: Firebug のソースを確認したところ、さらに多くのレイヤーのために4 つのステートメントがチェーン化されています。クレイジー!
const evalScript = "with (__win__.__scope__.vars) { with (__win__.__scope__.api) { with (__win__.__scope__.userVars) { with (__win__) {" +
"try {" +
"__win__.__scope__.callback(eval(__win__.__scope__.expr));" +
"} catch (exc) {" +
"__win__.__scope__.callback(exc, true);" +
"}" +
"}}}}";
はい、はい、はい。非常に合法的な使用法があります。時計:
with (document.getElementById("blah").style) {
background = "black";
color = "blue";
border = "1px solid green";
}
基本的に、他のDOMまたはCSSフックはwithの素晴らしい使用法です。「CloneNode」が未定義になり、邪魔にならないようにしてそれを可能にすることに決めない限り、グローバルスコープに戻るわけではありません。
Crockfordのスピードの不満は、新しいコンテキストがwithによって作成されることです。コンテキストは一般的に高価です。同意します。しかし、divを作成したばかりで、cssを設定するためのフレームワークが手元になく、15程度のCSSプロパティを手動で設定する必要がある場合、コンテキストの作成は、変数の作成と15の逆参照よりもおそらく安価です。
var element = document.createElement("div"),
elementStyle = element.style;
elementStyle.fontWeight = "bold";
elementStyle.fontSize = "1.5em";
elementStyle.color = "#55d";
elementStyle.marginLeft = "2px";
等...
with
あいまいさのない利点を提供する小さなヘルパー関数を定義できます。
var with_ = function (obj, func) { func (obj); };
with_ (object_name_here, function (_)
{
_.a = "foo";
_.b = "bar";
});
次のことができるので、ほとんど価値がないようです。
var o = incrediblyLongObjectNameThatNoOneWouldUse;
o.name = "Bob";
o.age = "50";
私はこれまで使用したことがなく、使用する理由がわかりません。また、お勧めしません。
問題with
は、ECMAScript 実装が実行できる多数の字句最適化が妨げられることです。高速な JIT ベースのエンジンの台頭を考えると、この問題はおそらく近い将来さらに重要になるでしょう。
よりクリーンな構成を可能にしているように見えるかもしれませんがwith
(たとえば、一般的な無名関数ラッパーの代わりに新しいスコープを導入したり、冗長なエイリアシングを置き換えたりする場合)、 実際には価値がありません。パフォーマンスが低下するだけでなく、間違ったオブジェクトのプロパティに割り当てられたり (注入されたスコープ内のオブジェクトでプロパティが見つからない場合)、おそらく誤ってグローバル変数を導入したりする危険性が常にあります。IIRC、後者の問題は、Crockford が回避を推奨する動機となったものですwith
。
Visual Basic .NET にも同様のWith
ステートメントがあります。私がこれを使用する最も一般的な方法の 1 つは、多数のプロパティをすばやく設定することです。それ以外の:
someObject.Foo = ''
someObject.Bar = ''
someObject.Baz = ''
、私は書くことができます:
With someObject
.Foo = ''
.Bar = ''
.Baz = ''
End With
これは単なる怠惰の問題ではありません。また、はるかに読みやすいコードになります。.
また、JavaScript とは異なり、ステートメントの影響を受けるすべてのものの前に(ドット)を付ける必要があるため、あいまいさに悩まされることはありません。したがって、次の 2 つは明確に区別されます。
With someObject
.Foo = ''
End With
対。
With someObject
Foo = ''
End With
前者はsomeObject.Foo
; 後者はFoo
範囲外 someObject
です。
あいまいさのリスクが高すぎるため、JavaScript の区別の欠如により、Visual Basic のバリアントよりもはるかに有用性が低くなることがわかりました。それ以外にも、with
読みやすさを向上させる強力なアイデアがあります。
この小さなテンプレート エンジンwith
で行われているように、オブジェクトの内容をローカル変数としてブロックに導入するために使用できます。
使い方はショートカットだと思います。たとえば、オブジェクトを初期化する場合は、「ObjectName」を何度も入力するだけで済みます。Lisp の "with-slots" のようなもので、書くことができます
(with-slots (foo bar) objectname
"some code that accesses foo and bar"
これは書くことと同じです
"some code that accesses (slot-value objectname 'foo) and (slot-value objectname 'bar)""
言語で「Objectname.foo」が許可されている場合よりも、これがショートカットである理由は明らかですが、それでもなおです。
「with」を使用すると、コードをよりドライにすることができます。
次のコードを検討してください。
var photo = document.getElementById('photo');
photo.style.position = 'absolute';
photo.style.left = '10px';
photo.style.top = '10px';
次のように乾燥させることができます。
with(document.getElementById('photo').style) {
position = 'absolute';
left = '10px';
top = '10px';
}
読みやすさと表現力のどちらを好むかによると思います。
最初の例はより読みやすく、おそらくほとんどのコードに推奨されます。しかし、とにかくほとんどのコードはかなり飼いならされています。2 番目のものはもう少しあいまいですが、言語の表現力を利用してコード サイズと余分な変数を削減します。
Java や C# が好きな人は最初の方法 (object.member) を選び、Ruby や Python が好きな人は後者を選ぶと思います。
Delphi の経験があるので、 withを使用するのは最終手段のサイズ最適化であり、安全性を検証するために静的コード分析にアクセスできるある種の JavaScript ミニマイザー アルゴリズムによって実行される可能性があります。
withステートメントを自由に使用することで発生する可能性のあるスコープの問題は、a** の王室の苦痛になる可能性があり、コードで he.. が起こっていることを理解するためにデバッグ セッションを経験することは望ましくありません。 、意図したグローバル変数または外部スコープ変数ではなく、オブジェクトメンバーまたは間違ったローカル変数をキャプチャしたことがわかります。
スコープを明確にするためにドットが必要な点で、VB のwithステートメントの方が優れていますが、Delphi のwithステートメントは、ヘアトリガーを備えた装填済みの銃であり、JavaScript のステートメントは同じ警告を正当化するのに十分類似しているように見えます。
with の使用は推奨されておらず、ECMAScript 5 厳密モードでは禁止されています。推奨される代替方法は、一時変数にアクセスするプロパティを持つオブジェクトを割り当てることです。
withステートメントを使用して、コードサイズを小さくしたり、プライベートクラスメンバーに使用したりできます。例:
// demo class framework
var Class= function(name, o) {
var c=function(){};
if( o.hasOwnProperty("constructor") ) {
c= o.constructor;
}
delete o["constructor"];
delete o["prototype"];
c.prototype= {};
for( var k in o ) c.prototype[k]= o[k];
c.scope= Class.scope;
c.scope.Class= c;
c.Name= name;
return c;
}
Class.newScope= function() {
Class.scope= {};
Class.scope.Scope= Class.scope;
return Class.scope;
}
// create a new class
with( Class.newScope() ) {
window.Foo= Class("Foo",{
test: function() {
alert( Class.Name );
}
});
}
(new Foo()).test();
withステートメントは、スコープを変更する場合に非常に役立ちます。これは、実行時に操作できる独自のグローバルスコープを持つために必要なものです。定数を設定したり、「toUpper」、「toLower」、「isNumber」、「clipNumber」などのようによく使用される特定のヘルパー関数を設定したりできます。
よく読むパフォーマンスの悪さについて:関数のスコープはパフォーマンスに影響を与えません。実際、私のFFでは、スコープ付き関数はスコープなしよりも高速に実行されます。
var o={x: 5},r, fnRAW= function(a,b){ return a*b; }, fnScoped, s, e, i;
with( o ) {
fnScoped= function(a,b){ return a*b; };
}
s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
r+= fnRAW(i,i);
}
e= Date.now();
console.log( (e-s)+"ms" );
s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
r+= fnScoped(i,i);
}
e= Date.now();
console.log( (e-s)+"ms" );
したがって、上記の方法でwithステートメントを使用しても、パフォーマンスに悪影響はありませんが、コードサイズが小さくなり、モバイルデバイスのメモリ使用量に影響を与えるため、優れた効果があります。
比較的複雑な環境で実行されるコードをコンテナーに入れるのに適しています。私はこれを使用して、「ウィンドウ」のローカル バインディングを作成し、Web ブラウザー用のコードを実行します。
オブジェクト リテラルの使用は興味深いと思います。たとえば、クロージャーを使用するためのドロップインの代替品です。
for(var i = nodes.length; i--;)
{
// info is namespaced in a closure the click handler can access!
(function(info)
{
nodes[i].onclick = function(){ showStuff(info) };
})(data[i]);
}
または、クロージャーに相当する with ステートメント
for(var i = nodes.length; i--;)
{
// info is namespaced in a closure the click handler can access!
with({info: data[i]})
{
nodes[i].onclick = function(){ showStuff(info) };
}
}
本当のリスクは、with ステートメントの一部ではない変数を誤って無視することだと思います。そのため、オブジェクト リテラルが with に渡されるのが好きです。コードに追加されたコンテキストでそれがどうなるかを正確に確認できます。
with を使用すると、多くの実装でコードが遅くなります。これは、すべてがルックアップ用の追加のスコープにラップされるためです。JavaScript で with を使用する正当な理由はありません。
いくつかの短いコードでは、放射モードではなく度モードsin
でなどの三角関数を使用したいと思います。cos
この目的のために、私はAngularDegree
オブジェクトを使用します:
AngularDegree = new function() {
this.CONV = Math.PI / 180;
this.sin = function(x) { return Math.sin( x * this.CONV ) };
this.cos = function(x) { return Math.cos( x * this.CONV ) };
this.tan = function(x) { return Math.tan( x * this.CONV ) };
this.asin = function(x) { return Math.asin( x ) / this.CONV };
this.acos = function(x) { return Math.acos( x ) / this.CONV };
this.atan = function(x) { return Math.atan( x ) / this.CONV };
this.atan2 = function(x,y) { return Math.atan2(x,y) / this.CONV };
};
with
次に、ブロック内で言語ノイズを増やすことなく、度数モードで三角関数を使用できます。
function getAzimut(pol,pos) {
...
var d = pos.lon - pol.lon;
with(AngularDegree) {
var z = atan2( sin(d), cos(pol.lat)*tan(pos.lat) - sin(pol.lat)*cos(d) );
return z;
}
}
つまり、オブジェクトを関数のコレクションとして使用し、制限されたコード領域で直接アクセスできるようにします。これは便利だと思います。
with
私は、次のステートメントでこのあいまいさの一部を排除する「マージ」関数を作成しました。
if (typeof Object.merge !== 'function') {
Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another
for(var i in o2) { o1[i] = o2[i]; }
return o1;
};
}
と同様に使用できますがwith
、影響を与えるつもりのないスコープには影響しないことがわかります。
使用法:
var eDiv = document.createElement("div");
var eHeader = Object.merge(eDiv.cloneNode(false), {className: "header", onclick: function(){ alert("Click!"); }});
function NewObj() {
Object.merge(this, {size: 4096, initDate: new Date()});
}
object.member と入力するよりも with を使用する方が読みやすいとは思えません。読みにくいとは思いませんが、読みやすくもないと思います。
lassevk が言ったように、非常に明示的な「object.member」構文を使用するよりも、 with を使用するとエラーが発生しやすくなることが確実にわかります。
の有用性はwith
、コードがどれだけうまく書かれているかに依存すると思います。たとえば、次のようなコードを書いているとします。
var sHeader = object.data.header.toString();
var sContent = object.data.content.toString();
var sFooter = object.data.footer.toString();
with
次に、これを行うことでコードの可読性が向上すると主張できます。
var sHeader = null, sContent = null, sFooter = null;
with(object.data) {
sHeader = header.toString();
sContent = content.toString();
sFooter = content.toString();
}
逆に、デメテルの法則に違反していると主張することもできますが、そうではないかもしれません。余談=)。
何よりも、Douglas Crockford がを使用しないことwith
を推奨していることを知っておいてください。ここで、彼のブログ投稿with
とその代替案を確認することをお勧めします。
W3schools http://www.w3schools.com/js/js_form_validation.aspの JavaScript でフォームの検証を確認する必要があります。ここでは、オブジェクト フォームが「スキャン」されて「email」という名前の入力が検索されます。
しかし、フォーム内のフィールドの名前や数量に関係なく、すべてのフィールドが空ではないことを検証する任意のフォームから取得するように変更しました。さて、私はテキストフィールドのみをテストしました。
しかし with() は物事をより簡単にしました。コードは次のとおりです。
function validate_required(field)
{
with (field)
{
if (value==null||value=="")
{
alert('All fields are mandtory');return false;
}
else
{
return true;
}
}
}
function validate_form(thisform)
{
with (thisform)
{
for(fiie in elements){
if (validate_required(elements[fiie])==false){
elements[fiie].focus();
elements[fiie].style.border='1px solid red';
return false;
} else {elements[fiie].style.border='1px solid #7F9DB9';}
}
}
return false;
}
CoffeeScript のCocoフォークにはwith
キーワードがありますが、ブロック内のターゲット オブジェクトに設定するだけです (CoffeeScript/Coco のthis
ように書き込み可能)。@
これによりあいまいさが解消され、ES5 の厳格なモードへの準拠が達成されます。
with long.object.reference
@a = 'foo'
bar = @b
with
オブジェクトに格納されている値に基づいて、オブジェクトリテラルに新しい要素を追加するための良い使用法は次のとおりです。これが私が今日使用した例です:
使用できるタイルのセット(開口部が上、下、左、または右を向いている)があり、ゲームの開始時に常に配置およびロックされるタイルのリストをすばやく追加する方法が必要でした。 。types.tbr
リスト内のタイプごとに入力し続けたくなかったので、を使用しwith
ました。
Tile.types = (function(t,l,b,r) {
function j(a) { return a.join(' '); }
// all possible types
var types = {
br: j( [b,r]),
lbr: j([l,b,r]),
lb: j([l,b] ),
tbr: j([t,b,r]),
tbl: j([t,b,l]),
tlr: j([t,l,r]),
tr: j([t,r] ),
tl: j([t,l] ),
locked: []
};
// store starting (base/locked) tiles in types.locked
with( types ) { locked = [
br, lbr, lbr, lb,
tbr, tbr, lbr, tbl,
tbr, tlr, tbl, tbl,
tr, tlr, tlr, tl
] }
return types;
})("top","left","bottom","right");
Andy E が Shog9 の回答のコメントで指摘したようにwith
、オブジェクト リテラルを使用すると、予期しない動作が発生する可能性があります。
for (var i = 0; i < 3; i++) {
function toString() {
return 'a';
}
with ({num: i}) {
setTimeout(function() { console.log(num); }, 10);
console.log(toString()); // prints "[object Object]"
}
}
予期しない動作がの特徴ではなかったwith
わけではありません。
それでもこの手法を使用したい場合は、少なくとも null プロトタイプを持つオブジェクトを使用してください。
function scope(o) {
var ret = Object.create(null);
if (typeof o !== 'object') return ret;
Object.keys(o).forEach(function (key) {
ret[key] = o[key];
});
return ret;
}
for (var i = 0; i < 3; i++) {
function toString() {
return 'a';
}
with (scope({num: i})) {
setTimeout(function() { console.log(num); }, 10);
console.log(toString()); // prints "a"
}
}
ただし、これは ES5+ でのみ機能します。も使用しないでくださいwith
。
with
require.js を使用するときにアリティを明示的に管理する必要を回避するために使用できます。
var modules = requirejs.declare([{
'App' : 'app/app'
}]);
require(modules.paths(), function() { with (modules.resolve(arguments)) {
App.run();
}});
requirejs.declare の実装:
requirejs.declare = function(dependencyPairs) {
var pair;
var dependencyKeys = [];
var dependencyValues = [];
for (var i=0, n=dependencyPairs.length; i<n; i++) {
pair = dependencyPairs[i];
for (var key in dependencyPairs[i]) {
dependencyKeys.push(key);
dependencyValues.push(pair[key]);
break;
}
};
return {
paths : function() {
return dependencyValues;
},
resolve : function(args) {
var modules = {};
for (var i=0, n=args.length; i<n; i++) {
modules[dependencyKeys[i]] = args[i];
}
return modules;
}
}
}
アプリケーションの一部の動作を変更するために、ユーザーがコードをアップロードできるようにするプロジェクトに取り組んでいます。このシナリオでは、私はwith
句を使用して、彼らのコードが私が混乱させたい範囲外のものを変更しないようにしています。これを行うために使用するコードの(簡略化された)部分は次のとおりです。
// this code is only executed once
var localScope = {
build: undefined,
// this is where all of the values I want to hide go; the list is rather long
window: undefined,
console: undefined,
...
};
with(localScope) {
build = function(userCode) {
eval('var builtFunction = function(options) {' + userCode + '}');
return builtFunction;
}
}
var build = localScope.build;
delete localScope.build;
// this is how I use the build method
var userCode = 'return "Hello, World!";';
var userFunction = build(userCode);
このコードは、ユーザー定義コードがwindow
、クロージャーを介してローカル変数などのグローバルスコープのオブジェクトにもアクセスできないことを (ある程度) 保証します。
賢明な言葉として、ユーザーが送信したコードに対して静的コード チェックを実行し、他の卑劣な方法でグローバル スコープにアクセスしていないことを確認する必要があります。たとえば、次のユーザー定義コードは、 への直接アクセスを取得しますwindow
。
test = function() {
return this.window
};
return test();
独自の巧妙な方法で、きれいな構文とあいまいさのない「with()」機能を取得できることを追加したかっただけです...
//utility function
function _with(context){
var ctx=context;
this.set=function(obj){
for(x in obj){
//should add hasOwnProperty(x) here
ctx[x]=obj[x];
}
}
return this.set;
}
//how calling it would look in code...
_with(Hemisphere.Continent.Nation.Language.Dialect.Alphabet)({
a:"letter a",
b:"letter b",
c:"letter c",
d:"letter a",
e:"letter b",
f:"letter c",
// continue through whole alphabet...
});//look how readable I am!!!!
..または、あいまいさやカスタムメソッドなしで「with()」を本当に使用したい場合は、匿名関数でラップして.callを使用します
//imagine a deeply nested object
//Hemisphere.Continent.Nation.Language.Dialect.Alphabet
(function(){
with(Hemisphere.Continent.Nation.Language.Dialect.Alphabet){
this.a="letter a";
this.b="letter b";
this.c="letter c";
this.d="letter a";
this.e="letter b";
this.f="letter c";
// continue through whole alphabet...
}
}).call(Hemisphere.Continent.Nation.Language.Dialect.Alphabet)
ただし、他の人が指摘しているように、できるので少し無意味です...
//imagine a deeply nested object Hemisphere.Continent.Nation.Language.Dialect.Alphabet
var ltr=Hemisphere.Continent.Nation.Language.Dialect.Alphabet
ltr.a="letter a";
ltr.b="letter b";
ltr.c="letter c";
ltr.d="letter a";
ltr.e="letter b";
ltr.f="letter c";
// continue through whole alphabet...